cryptlib  3.4.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros
msg_acl.c
Go to the documentation of this file.
1 /****************************************************************************
2 * *
3 * Message ACLs Handlers *
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 /****************************************************************************
23 * *
24 * Message ACLs *
25 * *
26 ****************************************************************************/
27 
28 /* Compare ACL for compare messages */
29 
30 static const COMPARE_ACL FAR_BSS compareACLTbl[] = {
31  /* Hash/MAC value */
34  16, CRYPT_MAX_HASHSIZE ) },
35 
36  /* ICV value */
39  12, CRYPT_MAX_HASHSIZE ) },
40 
41  /* PKC keyID */
44  2, 128 ) },
45 
46  /* PGP keyID */
50 
51  /* OpenPGP keyID */
55 
56  /* X.509 subject DN */
59  2, MAX_ATTRIBUTE_SIZE ) },
60 
61  /* PKCS #7 issuerAndSerialNumber */
64  2, MAX_ATTRIBUTE_SIZE ) },
65 
66  /* Certificate fingerprint for various hash algorithms */
69  20, 20 ) },
72  32, 32 ) },
75  32, 32 ) },
76 
77  /* Certificate object */
81 
82  /* End-of-ACL marker */
84  MK_CMPACL_END() },
86  MK_CMPACL_END() }
87  };
88 
89 /* Check ACL for check messages */
90 
91 #define PUBKEY_CERT_OBJECT ( ST_CERT_CERT | ST_CERT_ATTRCERT | \
92  ST_CERT_CERTCHAIN | ST_CERT_CERTREQ | \
93  ST_CERT_REQ_CERT )
94 #define PUBKEY_KEYSET_OBJECT ( ST_KEYSET_FILE | ST_KEYSET_FILE_PARTIAL | \
95  ST_KEYSET_FILE_RO | ST_KEYSET_DBMS | \
96  ST_KEYSET_DBMS_STORE | ST_KEYSET_HTTP | \
97  ST_KEYSET_LDAP | ST_DEV_P11 | \
98  ST_DEV_CAPI | ST_DEV_HW )
99 #define PRIVKEY_KEYSET_OBJECT ( ST_KEYSET_FILE | ST_KEYSET_FILE_PARTIAL | \
100  ST_KEYSET_FILE_RO | ST_DEV_P11 | \
101  ST_DEV_CAPI | ST_DEV_HW )
102 
103 /* The certificate and CA capabilities are spread across certificates (the
104  certificate or certificate with CA flag set) and contexts (the PKC
105  capability), which requires a two-phase check. First we check the
106  primary object and then we check the secondary one. For a private key
107  the primary object is the private-key context and the secondary is the
108  certificate, for a public key the primary object is the certificate and
109  the secondary is the public-key context.
110 
111  Since the primary object has a dependent object but the secondary one
112  doesn't we have to change the check type that we perform on the secondary
113  to reflect this. The checking performed is therefore:
114 
115  Type Target Object Action Dep.Obj. Fded chk
116  ---- ------ ------ ------ ------- --------
117  Privkey + cert Context PKC PKC Cert CERTxx
118  Cert + pubkey Cert Cert PKC PKC PKC
119 
120  Type Target Object Action Dep.Obj. Fded chk
121  ---- ------ ------ ------ ------- --------
122  Privkey + CA cert Context PKC SIGN Cert CACERT
123  CA cert + pubkey Cert Cert SIGCHECK PKC SIGCHECK
124 
125  In theory for CA certificates we'd need to perform some sort of generic
126  sign-or-sigcheck check for the case where the certificate is the primary
127  object, but since the certificate + context combination can only occur
128  for public-key contexts it's safe to check for a SIGCHECK capability.
129  Similarly, when the context is the primary object it's always a private
130  key, so we can check for a SIGN capability */
131 
132 static const CHECK_ALT_ACL FAR_BSS checkCertACLTbl[] = {
138  MESSAGE_CHECK_PKC ) },
139 
140  /* End-of-ACL marker */
142  MK_CHKACL_ALT_END() },
145  };
146 static const CHECK_ALT_ACL FAR_BSS checkCAACLTbl[] = {
152  MESSAGE_CHECK_PKC_SIGCHECK ) },
153 
154  /* End-of-ACL marker */
156  MK_CHKACL_ALT_END() },
159  };
160 
161 static const CHECK_ACL FAR_BSS checkACLTbl[] = {
162  /* PKC actions. These get somewhat complex to check because the primary
163  message target may be a context or certificate object with an
164  associated public key so we have to allow both object types */
165  { MESSAGE_CHECK_PKC, /* Public or private key context */
168 
169  { MESSAGE_CHECK_PKC_PRIVATE, /* Private key context */
172 
173  { MESSAGE_CHECK_PKC_ENCRYPT, /* Public encryption context */
176 
177  { MESSAGE_CHECK_PKC_DECRYPT, /* Private decryption context */
180 
181  { MESSAGE_CHECK_PKC_SIGCHECK, /* Public signature check context */
184 
185  { MESSAGE_CHECK_PKC_SIGN, /* Private signature context */
188 
189  { MESSAGE_CHECK_PKC_KA_EXPORT, /* Key agreement - export context */
192 
193  { MESSAGE_CHECK_PKC_KA_IMPORT, /* Key agreement - import context */
196 
197  /* Conventional encryption/hash/MAC actions */
198  { MESSAGE_CHECK_CRYPT, /* Conventional encryption capability */
200  ST_CTX_CONV ) },
201 
202  { MESSAGE_CHECK_HASH, /* Hash capability */
204  ST_CTX_HASH ) },
205 
206  { MESSAGE_CHECK_MAC, /* MAC capability */
208  ST_CTX_MAC ) },
209 
210  /* Checks that an object is ready to be initialised to perform this
211  operation */
212  { MESSAGE_CHECK_CRYPT_READY, /* Ready for init for conv.encr.*/
215 
216  { MESSAGE_CHECK_MAC_READY, /* Ready for init for MAC */
219 
220  { MESSAGE_CHECK_KEYGEN_READY, /* Ready for init key generation */
223 
224  /* Checks on purely passive container objects that constrain action
225  objects (for example a certificate being attached to a context) for
226  which the state isn't important in this instance. Usually we check
227  to make sure that the certificate is in the high state, but when a
228  certificate is being created/imported it may not be in the high state
229  yet at the time the check is being carried out.
230 
231  In addition to certificates the message can be sent to a keyset to
232  check whether it contains keys capable of performing the required
233  action */
234  { MESSAGE_CHECK_PKC_ENCRYPT_AVAIL, /* Encryption available */
237  ACL_FLAG_ANY_STATE ) },
238 
239  { MESSAGE_CHECK_PKC_DECRYPT_AVAIL, /* Decryption available */
242  ACL_FLAG_ANY_STATE ) },
243 
244  { MESSAGE_CHECK_PKC_SIGCHECK_AVAIL, /* Signature check available */
247  ACL_FLAG_ANY_STATE ) },
248 
249  { MESSAGE_CHECK_PKC_SIGN_AVAIL, /* Signature available */
252  ACL_FLAG_ANY_STATE ) },
253 
254  { MESSAGE_CHECK_PKC_KA_EXPORT_AVAIL,/* Key agreement - export available */
257 
258  { MESSAGE_CHECK_PKC_KA_IMPORT_AVAIL,/* Key agreement - import available */
261 
262  /* Misc.actions. The certificate check is used to verify that a
263  certificate is generally valid (for example not expired) without
264  having to performing a full signature verification up to a trusted
265  root, this is used to verify certificates passed in as parameters
266  (for example server certificates) to ensure that the client doesn't
267  get invalid data back when it tries to connect to the server.
268  Because the certificate could be used for either signing or
269  encryption we don't perform any additional context-based checks but
270  just perform a check of the certificate object.
271 
272  The certificate/CA certificate capability is spread across
273  certificates and contexts, which requires a two-phase check specified
274  in a sub-ACL. The second phase (MESSAGE_CHECK_CERTxx/
275  MESSAGE_CHECK_CACERT) check is never applied directly but is the
276  second part of the two-phase check performed for the certificate/CA
277  capability, so that first the entry for MESSAGE_CHECK_CERT/
278  MESSAGE_CHECK_CA is used and then for the dependent object the
279  sub-ACL sets the check type to MESSAGE_CHECK_CERTxx/
280  MESSAGE_CHECK_CACERT, which applies the second entry in the main
281  ACL */
282  { MESSAGE_CHECK_CERT, /* Generic certificate */
283  MK_CHKACL_EXT( MESSAGE_NONE, ST_NONE, checkCertACLTbl ) },
284  { MESSAGE_CHECK_CERTxx, /* xx cert, part two of CHECK_CERT */
287 
288  { MESSAGE_CHECK_CA, /* Cert signing capability */
289  MK_CHKACL_EXT( MESSAGE_NONE, ST_NONE, checkCAACLTbl ) },
290  { MESSAGE_CHECK_CACERT, /* CA cert, part two of CHECK_CA */
293 
294  /* End-of-ACL marker */
296  MK_CHKACL_END() },
298  MK_CHKACL_END() }
299  };
300 
301 /* When we export a certificate the easiest way to handle the export check
302  is via a pseudo-ACL that's checked via the standard attribute ACL-
303  checking function. The following ACL handles certificate exports */
304 
305 static const ATTRIBUTE_ACL_ALT FAR_BSS formatPseudoACL[] = {
306  /* Encoded certificate data */
307  MKACL_S_ALT(
312  ROUTE( OBJECT_TYPE_CERTIFICATE ), RANGE( 64, 8192 ) ),
313 
314  /* Encoded certificate chain */
315  MKACL_S_ALT(
319  ROUTE( OBJECT_TYPE_CERTIFICATE ), RANGE( 64, 8192 ) ),
320 
321  /* Base64-encoded certificate */
322  MKACL_S_ALT(
326  ROUTE( OBJECT_TYPE_CERTIFICATE ), RANGE( 64, 8192 ) ),
327 
328  /* Base64-encoded certificate chain */
329  MKACL_S_ALT(
333  ROUTE( OBJECT_TYPE_CERTIFICATE ), RANGE( 64, 8192 ) ),
334 
335  /* XML-encoded certificate */
336  MKACL_S_ALT(
340  ROUTE( OBJECT_TYPE_CERTIFICATE ), RANGE( 64, 8192 ) ),
341 
342  /* XML-encoded certificate chain */
343  MKACL_S_ALT(
347  ROUTE( OBJECT_TYPE_CERTIFICATE ), RANGE( 64, 8192 ) ),
348 
349  /* SET OF certificate in chain */
350  MKACL_S_ALT(
351  CRYPT_ICERTFORMAT_CERTSET,
354  ROUTE( OBJECT_TYPE_CERTIFICATE ), RANGE( 16, 8192 ) ),
355 
356  /* SEQUENCE OF certificate in chain */
357  MKACL_S_ALT(
358  CRYPT_ICERTFORMAT_CERTSEQUENCE,
361  ROUTE( OBJECT_TYPE_CERTIFICATE ), RANGE( 16, 8192 ) ),
362 
363  /* SSL certificate chain */
364  MKACL_S_ALT(
365  CRYPT_ICERTFORMAT_SSL_CERTCHAIN,
368  ROUTE( OBJECT_TYPE_CERTIFICATE ), RANGE( 16, 8192 ) ),
369 
370  /* Encoded non-signed object data. We allow this attribute to be read
371  for objects in the high as well as the low state even though in
372  theory it's only present for low (non-signed) objects because the
373  object can be in the high state if it was imported from its external
374  encoded form */
375  MKACL_S_ALT(
376  CRYPT_ICERTFORMAT_DATA,
381  ROUTE( OBJECT_TYPE_CERTIFICATE ), RANGE( 64, 8192 ) ),
382 
383  /* End-of-ACL marker */
384  MKACL_S_ALT(
387  ROUTE( OBJECT_TYPE_NONE ), RANGE( 0, 0 ) ),
388  MKACL_S_ALT(
391  ROUTE( OBJECT_TYPE_NONE ), RANGE( 0, 0 ) )
392  };
393 
394 /* Create-object ACLs */
395 
396 static const CREATE_ACL FAR_BSS deviceSpecialACL = {
398  /* PKCS #11 and CryptoAPI devices must include a device name */
400  MKACP_N( 0, 0 ),
402  CRYPT_MAX_TEXTSIZE ), /* Device name */
403  MKACP_S_NONE() }
404  };
405 static const CREATE_ACL FAR_BSS createObjectACL[] = {
406  /* Context object */
409  MKACP_N( 0, 0 ),
410  MKACP_S_NONE(),
411  MKACP_S_NONE() } },
412 
413  /* Keyset object */
417  CRYPT_KEYOPT_LAST - 1 ), /* Keyset options (may be _NONE) */
419  MAX_ATTRIBUTE_SIZE - 1 ), /* Keyset name */
420  MKACP_S_NONE() } },
421 
422  /* Envelope object */
424  { MKACP_N( CRYPT_FORMAT_NONE + 1, CRYPT_FORMAT_LAST_EXTERNAL - 1 ),
425  MKACP_N( 0, 0 ),
426  MKACP_S_NONE(),
427  MKACP_S_NONE() } },
428 
429  /* Certificate object */
432  MKACP_N( 0, 0 ),
433  MKACP_S_NONE(),
434  MKACP_S_NONE() } },
435 
436  /* Device object */
439  MKACP_N( 0, 0 ),
440  MKACP_S_NONE(), /* See exception list */
441  MKACP_S_NONE() },
442  /* Exceptions: PKCS #11 and CryptoAPI devices have the device name as
443  the first string parameter */
444  { CRYPT_DEVICE_PKCS11, CRYPT_DEVICE_CRYPTOAPI }, &deviceSpecialACL },
445 
446  /* Session object */
449  MKACP_N( 0, 0 ),
450  MKACP_S_NONE(),
451  MKACP_S_NONE() } },
452 
453  /* User object */
456  MKACP_N( 0, 0 ),
458  CRYPT_MAX_TEXTSIZE ), /* User name */
460  CRYPT_MAX_TEXTSIZE ) } }, /* User password */
461 
462  /* End-of-ACL marker */
463  { OBJECT_TYPE_NONE, { { 0 } } },
464  { OBJECT_TYPE_NONE, { { 0 } } }
465  };
466 
467 /* Create-object-indirect ACLs */
468 
469 static const CREATE_ACL FAR_BSS certSpecialACL = {
471  /* PKCS #7/CMS certificate collections must include a identifier for
472  the leaf certificate in the collection, to allow the certificate-
473  import code to pick and assemble the required certificates into a
474  chain */
475  { MKACP_N( CRYPT_ICERTTYPE_CMS_CERTSET,
476  CRYPT_ICERTTYPE_CMS_CERTSET ),/* Cert.type hint */
477  MKACP_N( CRYPT_IKEYID_KEYID,
478  CRYPT_IKEYID_ISSUERANDSERIALNUMBER ),/* Key ID type */
479  MKACP_S( 16, MAX_INTLENGTH - 1 ), /* Cert.object data */
480  MKACP_S( 3, MAX_INTLENGTH - 1 ) } /* Key ID */
481  };
482 static const CREATE_ACL FAR_BSS createObjectIndirectACL[] = {
483  /* Certificate object instantiated from encoded data */
486  CRYPT_CERTTYPE_LAST - 1 ), /* Cert.type hint (may be _NONE) */
487  MKACP_N( 0, 0 ), /* See exception list */
488  MKACP_S( 16, MAX_INTLENGTH - 1 ), /* Cert.object data */
489  MKACP_S_NONE() }, /* See exception list */
490  /* Exception: CMS certificate-set objects have a key ID type as the
491  second integer argument and a key ID as the second string
492  argument */
493  { CRYPT_ICERTTYPE_CMS_CERTSET }, &certSpecialACL },
494 
495  { OBJECT_TYPE_NONE, { { 0 } } },
496  { OBJECT_TYPE_NONE, { { 0 } } }
497  };
498 
499 /****************************************************************************
500 * *
501 * Utility Functions *
502 * *
503 ****************************************************************************/
504 
505 /* Check whether a numeric value falls within a range */
506 
507 CHECK_RETVAL_BOOL \
508 static BOOLEAN checkNumericRange( const int value, const int lowRange,
509  const int highRange )
510  {
511  /* Precondition: The range values are either both negative or both
512  positive. This is needed for the range comparison to work */
513  REQUIRES_B( ( lowRange < 0 && highRange < 0 ) || \
514  ( lowRange >= 0 && highRange >= 0 && \
515  lowRange <= highRange ) );
516 
517  /* Check whether the value is within the allowed range. Since some
518  values can be negative (e.g. cursor movement codes) we have to
519  reverse the range check for negative values */
520  if( lowRange >= 0 )
521  {
522  /* Positive, it's a standard comparison */
523  if( value >= lowRange && value <= highRange )
524  return( TRUE );
525  }
526  else
527  {
528  REQUIRES_B( highRange <= lowRange );
529 
530  /* Negative, reverse the comparison */
531  if( value >= highRange && value <= lowRange )
532  return( TRUE );
533  }
534 
535  return( FALSE );
536  }
537 
538 /* Check whether a numeric value falls within a special-case range type */
539 
541 static BOOLEAN checkAttributeRangeSpecial( IN_ENUM( RANGEVAL ) \
542  const RANGEVAL_TYPE rangeType,
543  const void *rangeInfo,
544  const int value )
545  {
546  /* Precondition: The range checking information is valid */
547  REQUIRES_B( rangeType > RANGEVAL_NONE && rangeType < RANGEVAL_LAST );
548  REQUIRES_B( rangeInfo != NULL );
549 
550  /* RANGEVAL_ALLOWEDVALUES contains an int [] of permitted values,
551  terminated by CRYPT_ERROR */
552  if( rangeType == RANGEVAL_ALLOWEDVALUES )
553  {
554  const int *allowedValuesInfo = rangeInfo;
555  int i;
556 
557  for( i = 0; allowedValuesInfo[ i ] != CRYPT_ERROR && \
558  i < FAILSAFE_ITERATIONS_SMALL; i++ )
559  {
560  if( value == allowedValuesInfo[ i ] )
561  return( TRUE );
562  }
563  ENSURES( i < FAILSAFE_ITERATIONS_SMALL );
564  return( FALSE );
565  }
566 
567  /* RANGEVAL_SUBRANGES contains a SUBRANGE [] of allowed subranges,
568  terminated by { CRYPT_ERROR, CRYPT_ERROR } */
569  if( rangeType == RANGEVAL_SUBRANGES )
570  {
571  const RANGE_SUBRANGE_TYPE *allowedValuesInfo = rangeInfo;
572  int i;
573 
574  for( i = 0; allowedValuesInfo[ i ].lowRange != CRYPT_ERROR && \
575  i < FAILSAFE_ITERATIONS_SMALL; i++ )
576  {
577  if( checkNumericRange( value, allowedValuesInfo[ i ].lowRange,
578  allowedValuesInfo[ i ].highRange ) )
579  return( TRUE );
580  }
581  ENSURES( i < FAILSAFE_ITERATIONS_SMALL );
582  return( FALSE );
583  }
584 
586  }
587 
588 /* Check whether a string value falls within the given limits, with special
589  handling for widechar strings. This sort of thing really shouldn't be
590  in the kernel, but not having it here makes correct string length range
591  checking difficult */
592 
594 static BOOLEAN checkAttributeRangeWidechar( const void *value,
595  IN_LENGTH const int valueLength,
596  IN_LENGTH_Z const int minLength,
597  IN_LENGTH const int maxLength )
598  {
599 #ifdef USE_WIDECHARS
600  const wchar_t *wcString = value;
601 #endif /* USE_WIDECHARS */
602 
603  assert( isReadPtr( value, valueLength ) );
604 
605  REQUIRES_B( minLength >= 0 && maxLength >= 0 && \
606  minLength <= maxLength );
607 
608 #ifdef USE_WIDECHARS
609  /* If it's not a multiple of wchar_t in size or smaller than a
610  wchar_t, it can't be a widechar string */
611  if( ( valueLength % WCSIZE ) || ( valueLength < WCSIZE ) )
612  {
613  return( ( valueLength < minLength || valueLength > maxLength ) ? \
614  FALSE : TRUE );
615  }
616 
617  /* If wchar_t is > 16 bits and the bits above 16 are all zero, it's
618  definitely a widechar string. Note that some compilers will complain
619  of unreachable code here, unfortunately we can't easily fix this
620  since WCSIZE is usually an expression involving sizeof() which can't
621  be handled via the preprocessor so we have to guard it with a
622  preprocessor check */
623 #ifdef CHECK_WCSIZE
624  if( WCSIZE > 2 && *wcString < 0xFFFF )
625  {
626  return( ( valueLength < ( minLength * WCSIZE ) || \
627  valueLength > ( maxLength * WCSIZE ) ) ? \
628  FALSE : TRUE );
629  }
630 #endif /* > 16-bit machines */
631 
632  /* Now it gets tricky. The only thing that we can still safely check
633  for is something that's been bloated out into widechars from ASCII */
634  if( ( valueLength > WCSIZE * 2 ) && \
635  ( wcString[ 0 ] < 0xFF && wcString[ 1 ] < 0xFF ) )
636  {
637  return( ( valueLength < ( minLength * WCSIZE ) || \
638  valueLength > ( maxLength * WCSIZE ) ) ? \
639  FALSE : TRUE );
640  }
641 #endif /* USE_WIDECHARS */
642 
643  /* It's not a widechar string or we can't handle these, perform a
644  straight range check */
645  return( ( valueLength < minLength || valueLength > maxLength ) ? \
646  FALSE : TRUE );
647  }
648 
649 /* Check whether a given action is permitted for an object */
650 
652 static int checkActionPermitted( const OBJECT_INFO *objectInfoPtr,
654  {
655  const MESSAGE_TYPE localMessage = message & MESSAGE_MASK;
656  int requiredLevel, actualLevel;
657 
658  assert( isReadPtr( objectInfoPtr, sizeof( OBJECT_INFO ) ) );
659 
660  REQUIRES( isValidMessage( localMessage ) );
661 
662  /* Determine the required level for access. Like protection rings, the
663  lower the value, the higher the privilege level. Level 3 is all-access,
664  level 2 is internal-access only, level 1 is no access, and level 0 is
665  not-available (e.g. encryption for hash contexts) */
666  requiredLevel = objectInfoPtr->actionFlags & \
667  MK_ACTION_PERM( localMessage, ACTION_PERM_MASK );
668 
669  /* Make sure that the action is enabled at the required level */
670  if( isInternalMessage( message ) )
671  {
672  /* It's an internal message, the minimal permissions will do */
673  actualLevel = MK_ACTION_PERM( localMessage, ACTION_PERM_NONE_EXTERNAL );
674  }
675  else
676  {
677  /* It's an external message, we need full permissions for access */
678  actualLevel = MK_ACTION_PERM( localMessage, ACTION_PERM_ALL );
679  }
680  if( requiredLevel < actualLevel )
681  {
682  /* The required level is less than the actual level (e.g. level 2
683  access attempted from level 3), return more detailed information
684  about the problem */
685  return( ( ( requiredLevel >> ACTION_PERM_SHIFT( localMessage ) ) == ACTION_PERM_NOTAVAIL ) ? \
687  }
688 
689  return( CRYPT_OK );
690  }
691 
692 /* Find the appropriate check ACL for a given message type */
693 
694 CHECK_RETVAL \
695 static int findCheckACL( IN_ENUM( MESSAGE_CHECK ) const int messageValue,
696  IN_ENUM( OBJECT ) const OBJECT_TYPE objectType,
697  OUT_OPT_PTR_OPT const CHECK_ACL **checkACLptr,
698  OUT_OPT_PTR_OPT const CHECK_ALT_ACL **checkAltACLptr )
699  {
700  const CHECK_ACL *checkACL = NULL;
701  const CHECK_ALT_ACL *checkAltACL;
702 
703  assert( checkACLptr == NULL || \
704  isReadPtr( checkACLptr, sizeof( CHECK_ACL * ) ) );
705  assert( checkAltACLptr == NULL || \
706  isReadPtr( checkAltACLptr, sizeof( CHECK_ALT_ACL * ) ) );
707 
708  /* Precondition: It's a valid check message type */
709  REQUIRES( messageValue > MESSAGE_CHECK_NONE && \
710  messageValue < MESSAGE_CHECK_LAST );
711 
712  /* Clear return values */
713  if( checkACLptr != NULL )
714  *checkACLptr = NULL;
715  if( checkAltACLptr != NULL )
716  *checkAltACLptr = NULL;
717 
718  /* Find the appropriate ACL(s) for a given check type */
719  if( messageValue > MESSAGE_CHECK_NONE && \
720  messageValue < MESSAGE_CHECK_LAST )
721  checkACL = &checkACLTbl[ messageValue - 1 ];
722  ENSURES( checkACL != NULL );
723 
724  /* Inner precondition: We have the correct ACL */
725  REQUIRES( checkACL->checkType == messageValue );
726 
727  /* If there's a sub-ACL present, find the correct ACL for this object
728  type */
729  if( ( checkAltACL = checkACL->altACL ) != NULL )
730  {
731  int i;
732 
733  for( i = 0; checkAltACL[ i ].object != CRYPT_OBJECT_NONE && \
734  checkAltACL[ i ].object != objectType && \
735  i < FAILSAFE_ITERATIONS_MED; i++ );
736  ENSURES( i < FAILSAFE_ITERATIONS_MED );
737  if( checkAltACL[ i ].object == CRYPT_OBJECT_NONE )
738  return( CRYPT_ARGERROR_OBJECT );
739  checkAltACL = &checkAltACL[ i ];
740  if( checkAltACL->checkType > MESSAGE_CHECK_NONE && \
741  checkAltACL->checkType < MESSAGE_CHECK_LAST )
742  checkACL = &checkACLTbl[ checkAltACL->checkType - 1 ];
743  ENSURES( checkACL != NULL );
744  }
745 
746  /* Postcondition: There's a valid ACL present */
747  assert( isReadPtr( checkACL, sizeof( CHECK_ACL ) ) );
748  assert( checkACL->altACL == NULL || \
749  isReadPtr( checkAltACL, sizeof( CHECK_ALT_ACL ) ) );
750 
751  if( checkACLptr != NULL )
752  *checkACLptr = checkACL;
753  if( checkAltACLptr != NULL )
754  *checkAltACLptr = checkAltACL;
755 
756  return( CRYPT_OK );
757  }
758 
759 /****************************************************************************
760 * *
761 * Init/Shutdown Functions *
762 * *
763 ****************************************************************************/
764 
766 int initMessageACL( INOUT KERNEL_DATA *krnlDataPtr )
767  {
768  int i;
769 
770  assert( isWritePtr( krnlDataPtr, sizeof( KERNEL_DATA ) ) );
771 
772  /* Perform a consistency check on the compare ACL */
773  for( i = 0; compareACLTbl[ i ].compareType != MESSAGE_COMPARE_NONE && \
774  i < FAILSAFE_ARRAYSIZE( compareACLTbl, COMPARE_ACL ); i++ )
775  {
776  const COMPARE_ACL *compareACL = &compareACLTbl[ i ];
777 
778  ENSURES( compareACL->compareType > MESSAGE_COMPARE_NONE && \
779  compareACL->compareType < MESSAGE_COMPARE_LAST && \
780  compareACL->compareType == i + 1 );
781  if( ( compareACL->objectACL.subTypeA & ~( SUBTYPE_CLASS_A | \
782  ST_CTX_ANY | ST_CERT_ANY ) ) || \
783  compareACL->objectACL.subTypeB != ST_NONE || \
784  compareACL->objectACL.subTypeC != ST_NONE )
785  {
786  DEBUG_DIAG(( "Message ACLs inconsistent" ));
787  retIntError();
788  }
789  ENSURES( ( compareACL->objectACL.flags == 0 ) || \
790  ( compareACL->objectACL.flags == ACL_FLAG_HIGH_STATE ) );
791  if( paramInfo( compareACL, 0 ).valueType == PARAM_VALUE_STRING )
792  {
793  ENSURES( paramInfo( compareACL, 0 ).lowRange >= 2 && \
794  paramInfo( compareACL, 0 ).lowRange <= \
795  paramInfo( compareACL, 0 ).highRange && \
796  paramInfo( compareACL, 0 ).highRange <= MAX_ATTRIBUTE_SIZE );
797  }
798  else
799  {
800  ENSURES( paramInfo( compareACL, 0 ).valueType == PARAM_VALUE_OBJECT );
801  if( ( paramInfo( compareACL, 0 ).subTypeA & ~( SUBTYPE_CLASS_A | \
802  ST_CERT_ANY ) ) || \
803  paramInfo( compareACL, 0 ).subTypeB != ST_NONE || \
804  paramInfo( compareACL, 0 ).subTypeC != ST_NONE )
805  {
806  DEBUG_DIAG(( "Message ACLs inconsistent" ));
807  retIntError();
808  }
809  }
810  }
811  ENSURES( i < FAILSAFE_ARRAYSIZE( compareACLTbl, COMPARE_ACL ) );
812 
813  /* Perform a consistency check on the check ACL */
814  for( i = 0; checkACLTbl[ i ].checkType != MESSAGE_CHECK_NONE && \
815  i < FAILSAFE_ARRAYSIZE( checkACLTbl, CHECK_ACL ); i++ )
816  {
817  const CHECK_ACL *checkACL = &checkACLTbl[ i ];
818  int j;
819 
820  ENSURES( checkACL->checkType > MESSAGE_CHECK_NONE && \
821  checkACL->checkType < MESSAGE_CHECK_LAST && \
822  checkACL->checkType == i + 1 );
823  ENSURES( checkACL->actionType == MESSAGE_NONE || \
824  ( checkACL->actionType >= MESSAGE_CTX_ENCRYPT && \
825  checkACL->actionType <= MESSAGE_CRT_SIGCHECK ) );
826  if( ( checkACL->objectACL.subTypeA & \
827  ~( SUBTYPE_CLASS_A | ST_CTX_ANY | ST_CERT_ANY ) ) || \
828  ( checkACL->objectACL.subTypeB & \
830  checkACL->objectACL.subTypeC != ST_NONE )
831  {
832  DEBUG_DIAG(( "Check ACLs inconsistent" ));
833  retIntError();
834  }
835  ENSURES( !( checkACL->objectACL.flags & ~ACL_FLAG_ANY_STATE ) )
836  if( checkACL->altACL == NULL )
837  continue;
838  for( j = 0; checkACL->altACL[ j ].object != OBJECT_TYPE_NONE && \
839  j < FAILSAFE_ITERATIONS_MED; j++ )
840  {
841  const CHECK_ALT_ACL *checkAltACL = &checkACL->altACL[ j ];
842 
843  ENSURES( checkAltACL->object == OBJECT_TYPE_CONTEXT || \
844  checkAltACL->object == OBJECT_TYPE_CERTIFICATE );
845  ENSURES( checkAltACL->checkType > MESSAGE_CHECK_NONE && \
846  checkAltACL->checkType < MESSAGE_CHECK_LAST );
847  ENSURES( checkAltACL->depObject == OBJECT_TYPE_CONTEXT || \
848  checkAltACL->depObject == OBJECT_TYPE_CERTIFICATE );
849  if( ( checkAltACL->depObjectACL.subTypeA & \
850  ~( SUBTYPE_CLASS_A | ST_CTX_ANY | ST_CERT_ANY ) ) || \
851  checkAltACL->depObjectACL.subTypeB != ST_NONE || \
852  checkAltACL->depObjectACL.subTypeC != ST_NONE )
853  {
854  DEBUG_DIAG(( "Check ACLs inconsistent" ));
855  retIntError();
856  }
857  ENSURES( !( checkAltACL->depObjectACL.flags & ~ACL_FLAG_ANY_STATE ) )
858  ENSURES( checkAltACL->fdCheckType > MESSAGE_CHECK_NONE && \
859  checkAltACL->fdCheckType < MESSAGE_CHECK_LAST );
860  }
861  ENSURES( j < FAILSAFE_ITERATIONS_MED );
862  }
863  ENSURES( i < FAILSAFE_ARRAYSIZE( checkACLTbl, CHECK_ACL ) );
864 
865  /* Perform a consistency check on the certificate export pseudo-ACL */
866  for( i = 0; formatPseudoACL[ i ].attribute != CRYPT_CERTFORMAT_NONE && \
867  i < FAILSAFE_ARRAYSIZE( formatPseudoACL, ATTRIBUTE_ACL_ALT );
868  i++ )
869  {
870  const ATTRIBUTE_ACL_ALT *formatACL = &formatPseudoACL[ i ];
871 
872  ENSURES( formatACL->attribute > CRYPT_CERTTYPE_NONE && \
873  formatACL->attribute < CRYPT_CERTTYPE_LAST );
874  if( ( formatACL->subTypeA & ~( SUBTYPE_CLASS_A | ST_CERT_ANY ) ) || \
875  formatACL->subTypeB != ST_NONE || \
876  formatACL->subTypeC != ST_NONE )
877  {
878  DEBUG_DIAG(( "Certificate export ACLs inconsistent" ));
879  retIntError();
880  }
881  if( formatACL->attribute < CRYPT_CERTFORMAT_LAST_EXTERNAL )
882  {
883  ENSURES( formatACL->access == ACCESS_Rxx_xxx );
884  }
885  else
886  {
887  ENSURES( formatACL->access == ACCESS_INT_Rxx_xxx || \
888  formatACL->access == ACCESS_INT_Rxx_Rxx );
889  }
890  ENSURES( formatACL->valueType == ATTRIBUTE_VALUE_STRING && \
891  formatACL->lowRange >= 16 && \
892  formatACL->lowRange < formatACL->highRange && \
893  formatACL->highRange <= 8192 && \
894  formatACL->extendedInfo == NULL );
895  }
896  ENSURES( i < FAILSAFE_ARRAYSIZE( formatPseudoACL, ATTRIBUTE_ACL_ALT ) );
897 
898  /* Perform a consistency check on the create-object ACL */
899  for( i = 0; createObjectACL[ i ].type != OBJECT_TYPE_NONE && \
900  i < FAILSAFE_ARRAYSIZE( createObjectACL, CREATE_ACL );
901  i++ )
902  {
903  const CREATE_ACL *createACL = &createObjectACL[ i ];
904 
905  ENSURES( isValidType( createACL->type ) );
906  ENSURES( paramInfo( createACL, 0 ).valueType == PARAM_VALUE_NUMERIC && \
907  paramInfo( createACL, 1 ).valueType == PARAM_VALUE_NUMERIC && \
908  ( paramInfo( createACL, 2 ).valueType == PARAM_VALUE_STRING_NONE || \
909  paramInfo( createACL, 2 ).valueType == PARAM_VALUE_STRING ) && \
910  ( paramInfo( createACL, 3 ).valueType == PARAM_VALUE_STRING_NONE || \
911  paramInfo( createACL, 3 ).valueType == PARAM_VALUE_STRING ) );
912  if( createACL->type == OBJECT_TYPE_CONTEXT )
913  {
914  ENSURES( paramInfo( createACL, 0 ).lowRange > CRYPT_ALGO_NONE && \
915  paramInfo( createACL, 0 ).highRange < CRYPT_ALGO_LAST );
916  }
917  else
918  {
919  /* Perform a composite check for a vaguely sensible value.
920  CRYPT_CERTTYPE_LAST is the highest possible value for all of
921  the non-context object types */
922  ENSURES( paramInfo( createACL, 0 ).lowRange > 0 && \
923  paramInfo( createACL, 0 ).highRange < CRYPT_CERTTYPE_LAST );
924  }
925  if( createACL->exceptions[ 0 ] == 0 && \
926  createACL->exceptions[ 1 ] != 0 )
927  {
928  DEBUG_DIAG(( "Create-object ACLs inconsistent" ));
929  retIntError();
930  }
931  if( ( createACL->exceptions[ 0 ] != 0 || \
932  createACL->exceptions[ 1 ] != 0 ) && \
933  createACL->exceptionACL == NULL )
934  {
935  DEBUG_DIAG(( "Create-object ACLs inconsistent" ));
936  retIntError();
937  }
938  }
939  ENSURES( i < FAILSAFE_ARRAYSIZE( createObjectACL, CREATE_ACL ) );
940 
941  /* Perform a consistency check on the create-object-indirect ACL */
942  for( i = 0; createObjectIndirectACL[ i ].type != OBJECT_TYPE_NONE && \
943  i < FAILSAFE_ARRAYSIZE( createObjectIndirectACL, CREATE_ACL );
944  i++ )
945  {
946  const CREATE_ACL *createACL = &createObjectIndirectACL[ i ];
947 
948  ENSURES( isValidType( createACL->type ) );
949  if( paramInfo( createACL, 0 ).valueType != PARAM_VALUE_NUMERIC || \
950  paramInfo( createACL, 1 ).valueType != PARAM_VALUE_NUMERIC || \
951  paramInfo( createACL, 2 ).valueType != PARAM_VALUE_STRING || \
952  ( paramInfo( createACL, 3 ).valueType != PARAM_VALUE_STRING_NONE && \
953  paramInfo( createACL, 3 ).valueType != PARAM_VALUE_STRING ) )
954  {
955  DEBUG_DIAG(( "Create-object indirect ACLs inconsistent" ));
956  retIntError();
957  }
958  ENSURES( paramInfo( createACL, 0 ).lowRange >= 0 && \
959  paramInfo( createACL, 0 ).highRange < CRYPT_CERTTYPE_LAST );
960  /* The low-range may be 0, which indicates that we're using
961  automatic format detection */
962  ENSURES( paramInfo( createACL, 2 ).lowRange >= 16 && \
963  paramInfo( createACL, 2 ).highRange < MAX_INTLENGTH );
964  if( createACL->exceptions[ 0 ] == 0 && \
965  createACL->exceptions[ 1 ] != 0 )
966  {
967  DEBUG_DIAG(( "Create-object ACLs inconsistent" ));
968  retIntError();
969  }
970  if( ( createACL->exceptions[ 0 ] != 0 || \
971  createACL->exceptions[ 1 ] != 0 ) && \
972  createACL->exceptionACL == NULL )
973  {
974  DEBUG_DIAG(( "Create-object ACLs inconsistent" ));
975  retIntError();
976  }
977  }
978  ENSURES( i < FAILSAFE_ARRAYSIZE( createObjectIndirectACL, CREATE_ACL ) );
979 
980  /* Set up the reference to the kernel data block */
981  krnlData = krnlDataPtr;
982 
983  return( CRYPT_OK );
984  }
985 
986 void endMessageACL( void )
987  {
988  krnlData = NULL;
989  }
990 
991 /****************************************************************************
992 * *
993 * Message Pre-dispatch Handlers *
994 * *
995 ****************************************************************************/
996 
997 /* If it's a destroy object message, adjust the reference counts of any
998  dependent objects and set the object's state to signalled. We do this
999  before we send the destroy message to the object in order that any
1000  further attempts to access it will fail. This is handled anyway by the
1001  message dispatcher, but setting the status to signalled now means that
1002  it's rejected immediately rather than being enqueued and then dequeued
1003  again once the destroy message has been processed */
1004 
1005 CHECK_RETVAL \
1006 int preDispatchSignalDependentObjects( IN_HANDLE const int objectHandle,
1008  STDC_UNUSED const void *dummy2,
1009  STDC_UNUSED const int dummy3,
1010  STDC_UNUSED const void *dummy4 )
1011  {
1012  OBJECT_INFO *objectInfoPtr = &krnlData->objectTable[ objectHandle ];
1013  STDC_UNUSED int status;
1014 
1015  /* Preconditions */
1016  REQUIRES( isValidObject( objectHandle ) && \
1017  objectHandle >= NO_SYSTEM_OBJECTS );
1018 
1019  /* An inability to change the reference counts of the dependent objects
1020  doesn't affect the object itself so we can't report it as an error,
1021  however we can at least warn about it in debug mode */
1022  if( isValidObject( objectInfoPtr->dependentDevice ) )
1023  {
1024  /* Velisurmaaja */
1025  status = decRefCount( objectInfoPtr->dependentDevice, 0, NULL, TRUE );
1026  assert( cryptStatusOK( status ) );
1027  }
1028  if( isValidObject( objectInfoPtr->dependentObject ) )
1029  {
1030  status = decRefCount( objectInfoPtr->dependentObject, 0, NULL, TRUE );
1031  assert( cryptStatusOK( status ) );
1032  }
1033  objectInfoPtr->flags |= OBJECT_FLAG_SIGNALLED;
1034 
1035  /* Postcondition: The object is now in the destroyed state as far as
1036  other objects are concerned */
1037  ENSURES( isInvalidObjectState( objectHandle ) );
1038 
1039  return( CRYPT_OK );
1040  }
1041 
1042 /* If it's an attribute get/set/delete, check the access conditions for the
1043  object and the message parameters */
1044 
1046 int preDispatchCheckAttributeAccess( IN_HANDLE const int objectHandle,
1047  IN_MESSAGE const MESSAGE_TYPE message,
1048  IN_OPT const void *messageDataPtr,
1049  IN_ATTRIBUTE const int messageValue,
1050  IN TYPECAST( ATTRIBUTE_ACL * ) \
1051  const void *auxInfo )
1052  {
1053  static const int FAR_BSS accessTypeTbl[ 7 ][ 2 ] = {
1054  /* MESSAGE_GETATTRIBUTE */ /* MESSAGE_GETATTRIBUTE_S */
1056  /* MESSAGE_SETATTRIBUTE */ /* MESSAGE_SETATTRIBUTE_S */
1058  /* MESSAGE_DELETEATTRIBUTE */
1062  };
1063  const ATTRIBUTE_ACL *attributeACL = ( ATTRIBUTE_ACL * ) auxInfo;
1064  const OBJECT_INFO *objectTable = krnlData->objectTable;
1065  const OBJECT_INFO *objectInfo = &objectTable[ objectHandle ];
1066  const MESSAGE_TYPE localMessage = message & MESSAGE_MASK;
1067  const int subType = objectInfo->subType;
1068  int accessType;
1069  const BOOLEAN isInternalMessage = isInternalMessage( message ) ? \
1070  TRUE : FALSE;
1071 
1072  assert( isReadPtr( attributeACL, sizeof( ATTRIBUTE_ACL ) ) );
1073  assert( attributeACL->attribute == messageValue );
1074  /* Only in debug build, see comment in attr_acl.c */
1075 
1076  /* Preconditions */
1077  REQUIRES( isValidType( objectInfo->type ) );
1078  REQUIRES( isAttributeMessage( localMessage ) );
1079  REQUIRES( isAttribute( messageValue ) || \
1080  isInternalAttribute( messageValue ) );
1081  REQUIRES( localMessage == MESSAGE_DELETEATTRIBUTE || \
1082  messageDataPtr != NULL );
1083  REQUIRES( localMessage - MESSAGE_GETATTRIBUTE >= 0 && \
1084  localMessage - MESSAGE_GETATTRIBUTE < 5 );
1085 
1086  /* Get the access permission for this message */
1087  accessType = accessTypeTbl[ localMessage - MESSAGE_GETATTRIBUTE ]\
1088  [ ( objectInfo->flags & OBJECT_FLAG_HIGH ) ? 1 : 0 ];
1089 
1090  /* If it's an internal message, use the internal access permssions */
1091  if( isInternalMessage )
1092  accessType = MK_ACCESS_INTERNAL( accessType );
1093 
1094  /* Make sure that the attribute is valid for this object subtype */
1095  if( !isValidSubtype( attributeACL->subTypeA, subType ) && \
1096  !isValidSubtype( attributeACL->subTypeB, subType ) && \
1097  !isValidSubtype( attributeACL->subTypeC, subType ) )
1098  return( CRYPT_ARGERROR_VALUE );
1099 
1100  /* Make sure that this type of access is valid for this attribute */
1101  if( !( attributeACL->access & accessType ) )
1102  {
1103  /* If it's an internal-only attribute being accessed through an
1104  external message then it isn't visible to the user so we return
1105  an attribute value error */
1106  if( !( attributeACL->access & ACCESS_MASK_EXTERNAL ) && \
1107  !isInternalMessage )
1108  return( CRYPT_ARGERROR_VALUE );
1109 
1110  /* It is visible, return a standard permission error */
1111  return( CRYPT_ERROR_PERMISSION );
1112  }
1113 
1114  /* Inner precondition: The attribute is valid for this subtype and is
1115  externally visible or it's an internal message, and this type of
1116  access is allowed */
1117  REQUIRES( isValidSubtype( attributeACL->subTypeA, subType ) || \
1118  isValidSubtype( attributeACL->subTypeB, subType ) || \
1119  isValidSubtype( attributeACL->subTypeC, subType ) );
1120  REQUIRES( ( attributeACL->access & ACCESS_MASK_EXTERNAL ) || \
1121  isInternalMessage );
1122  REQUIRES( attributeACL->access & accessType );
1123 
1124  /* If it's a delete attribute message then there's no attribute data
1125  being communicated, so we can exit now */
1126  if( localMessage == MESSAGE_DELETEATTRIBUTE )
1127  {
1128  ENSURES( messageDataPtr == NULL );
1129 
1130  return( CRYPT_OK );
1131  }
1132 
1133  /* Inner precondition: We're getting or setting the value of an attribute */
1134  REQUIRES( localMessage == MESSAGE_GETATTRIBUTE || \
1135  localMessage == MESSAGE_GETATTRIBUTE_S || \
1136  localMessage == MESSAGE_SETATTRIBUTE || \
1137  localMessage == MESSAGE_SETATTRIBUTE_S );
1138 
1139  /* Safety check for invalid pointers passed from an internal function */
1140  if( attributeACL->valueType != ATTRIBUTE_VALUE_SPECIAL && \
1141  !isReadPtr( messageDataPtr, \
1142  ( attributeACL->valueType == ATTRIBUTE_VALUE_STRING || \
1143  attributeACL->valueType == ATTRIBUTE_VALUE_WCSTRING || \
1144  attributeACL->valueType == ATTRIBUTE_VALUE_TIME ) ? \
1145  sizeof( MESSAGE_DATA ) : sizeof( int ) ) )
1146  retIntError();
1147 
1148  /* Make sure that the attribute type matches the supplied value type.
1149  We assert the preconditions for internal messages before the general
1150  check to ensure that we throw an exception rather than just returning
1151  an error code for internal programming errors */
1152  switch( attributeACL->valueType )
1153  {
1155  /* Inner precondition: If it's an internal message then it must
1156  be a numeric value */
1157  assert( isReadPtr( messageDataPtr, sizeof( int ) ) );
1158 
1159  REQUIRES( !isInternalMessage || \
1160  localMessage == MESSAGE_GETATTRIBUTE || \
1161  localMessage == MESSAGE_SETATTRIBUTE );
1162 
1163  /* Must be a numeric value */
1164  if( localMessage != MESSAGE_GETATTRIBUTE && \
1165  localMessage != MESSAGE_SETATTRIBUTE )
1166  return( CRYPT_ARGERROR_VALUE );
1167 
1168  /* If we're sending the data back to the caller, the only thing
1169  that we can check is the presence of a writeable output
1170  buffer */
1171  if( localMessage == MESSAGE_GETATTRIBUTE )
1172  {
1173  if( !isWritePtrConst( ( void * ) messageDataPtr, sizeof( int ) ) )
1174  return( CRYPT_ARGERROR_STR1 );
1175  }
1176  break;
1177 
1179  {
1180  const int *valuePtr = messageDataPtr;
1181 
1182  /* Inner precondition: If it's an internal message then it must
1183  be a numeric value */
1184  assert( isReadPtr( messageDataPtr, sizeof( int ) ) );
1185 
1186  REQUIRES( !isInternalMessage || \
1187  localMessage == MESSAGE_GETATTRIBUTE || \
1188  localMessage == MESSAGE_SETATTRIBUTE );
1189 
1190  /* Must be a numeric value */
1191  if( localMessage != MESSAGE_GETATTRIBUTE && \
1192  localMessage != MESSAGE_SETATTRIBUTE )
1193  return( CRYPT_ARGERROR_VALUE );
1194 
1195  /* If we're sending the data back to the caller, the only thing
1196  that we can check is the presence of a writeable output
1197  buffer */
1198  if( localMessage == MESSAGE_GETATTRIBUTE )
1199  {
1200  if( !isWritePtrConst( ( void * ) messageDataPtr, sizeof( int ) ) )
1201  return( CRYPT_ARGERROR_STR1 );
1202  break;
1203  }
1204 
1205  /* Inner precondition: We're sending data to the object */
1206  REQUIRES( localMessage == MESSAGE_SETATTRIBUTE );
1207 
1208  /* If it's a standard range check, make sure that the attribute
1209  value is within the allowed range */
1210  if( !isSpecialRange( attributeACL ) )
1211  {
1212  if( !checkNumericRange( *valuePtr, attributeACL->lowRange,
1213  attributeACL->highRange ) )
1214  return( CRYPT_ARGERROR_NUM1 );
1215  break;
1216  }
1217 
1218  /* It's a special-case range check */
1219  REQUIRES( isSpecialRange( attributeACL ) );
1220  switch( getSpecialRangeType( attributeACL ) )
1221  {
1222  case RANGEVAL_ANY:
1223  break;
1224 
1226  if( !checkAttributeRangeSpecial( RANGEVAL_ALLOWEDVALUES,
1227  getSpecialRangeInfo( attributeACL ),
1228  *valuePtr ) )
1229  return( CRYPT_ARGERROR_NUM1 );
1230  break;
1231 
1232  case RANGEVAL_SUBRANGES:
1233  if( !checkAttributeRangeSpecial( RANGEVAL_SUBRANGES,
1234  getSpecialRangeInfo( attributeACL ),
1235  *valuePtr ) )
1236  return( CRYPT_ARGERROR_NUM1 );
1237  break;
1238 
1239  default:
1240  retIntError();
1241  }
1242  break;
1243  }
1244 
1246  {
1247  const OBJECT_ACL *objectACL = attributeACL->extendedInfo;
1248  const int *valuePtr = messageDataPtr;
1249  int objectParamHandle, objectParamSubType;
1250 
1251  /* Inner precondition: If it's an internal message then it must
1252  be a numeric value */
1253  assert( isReadPtr( messageDataPtr, sizeof( int ) ) );
1254 
1255  REQUIRES( !isInternalMessage || \
1256  localMessage == MESSAGE_GETATTRIBUTE || \
1257  localMessage == MESSAGE_SETATTRIBUTE );
1258 
1259  /* Must be a numeric value */
1260  if( localMessage != MESSAGE_GETATTRIBUTE && \
1261  localMessage != MESSAGE_SETATTRIBUTE )
1262  return( CRYPT_ARGERROR_VALUE );
1263 
1264  /* If we're sending the data back to the caller, the only thing
1265  that we can check is the presence of a writeable output
1266  buffer */
1267  if( localMessage == MESSAGE_GETATTRIBUTE )
1268  {
1269  if( !isWritePtrConst( ( void * ) messageDataPtr, sizeof( int ) ) )
1270  return( CRYPT_ARGERROR_STR1 );
1271  break;
1272  }
1273 
1274  /* Inner precondition: We're sending data to the object */
1275  REQUIRES( localMessage == MESSAGE_SETATTRIBUTE );
1276 
1277  /* Must contain a valid object handle */
1278  if( !fullObjectCheck( *valuePtr, message ) || \
1279  !isSameOwningObject( objectHandle, *valuePtr ) )
1280  return( CRYPT_ARGERROR_NUM1 );
1281 
1282  /* Object must be of the correct type */
1283  if( objectACL->flags & ACL_FLAG_ROUTE_TO_CTX )
1284  {
1285  objectParamHandle = findTargetType( *valuePtr,
1287  }
1288  else
1289  {
1290  if( objectACL->flags & ACL_FLAG_ROUTE_TO_CERT )
1291  objectParamHandle = findTargetType( *valuePtr,
1293  else
1294  objectParamHandle = *valuePtr;
1295  }
1296  if( cryptStatusError( objectParamHandle ) )
1297  return( CRYPT_ARGERROR_NUM1 );
1298  objectParamSubType = objectTable[ objectParamHandle ].subType;
1299  if( !isValidSubtype( objectACL->subTypeA, objectParamSubType ) && \
1300  !isValidSubtype( objectACL->subTypeB, objectParamSubType ) && \
1301  !isValidSubtype( objectACL->subTypeC, objectParamSubType ) )
1302  return( CRYPT_ARGERROR_NUM1 );
1303  if( ( objectACL->flags & ACL_FLAG_STATE_MASK ) && \
1304  !checkObjectState( objectACL->flags, objectParamHandle ) )
1305  return( CRYPT_ARGERROR_NUM1 );
1306 
1307  /* Postcondition: Object parameter is valid and accessible,
1308  object is of the correct type and state */
1309  ENSURES( fullObjectCheck( *valuePtr, message ) && \
1310  isSameOwningObject( objectHandle, *valuePtr ) );
1311  ENSURES( isValidSubtype( objectACL->subTypeA, \
1312  objectParamSubType ) || \
1313  isValidSubtype( objectACL->subTypeB, \
1314  objectParamSubType ) || \
1315  isValidSubtype( objectACL->subTypeC, \
1316  objectParamSubType ) );
1317  ENSURES( !( objectACL->flags & ACL_FLAG_STATE_MASK ) || \
1318  checkObjectState( objectACL->flags, \
1319  objectParamHandle ) );
1320  break;
1321  }
1322 
1325  {
1327 
1328  /* Inner precondition: If it's an internal message then it must
1329  be a valid string value or a null value if we're obtaining a
1330  length. Polled entropy data can be arbitrarily large so we
1331  don't check its length */
1332  assert( isReadPtr( messageDataPtr, sizeof( MESSAGE_DATA ) ) );
1333  assert( !isInternalMessage || \
1334  ( ( localMessage == MESSAGE_GETATTRIBUTE_S && \
1335  ( ( msgData->data == NULL && msgData->length == 0 ) || \
1336  ( msgData->length >= 1 && \
1337  msgData->length < MAX_INTLENGTH && \
1338  isWritePtr( msgData->data, msgData->length ) ) ) ) || \
1339  ( localMessage == MESSAGE_SETATTRIBUTE_S && \
1340  isReadPtr( msgData->data, msgData->length ) && \
1341  ( ( msgData->length > 0 && \
1342  msgData->length < MAX_INTLENGTH_SHORT ) || \
1343  messageValue == CRYPT_IATTRIBUTE_ENTROPY ) ) ) );
1344 
1345  /* Note that the assert()/REQUIRES() appears to be duplicated
1346  but differs in some minor details, we use isReadPtr() in the
1347  debug version with assert() but only a more basic check for
1348  NULL in all versions with REQUIRES() */
1349  REQUIRES( !isInternalMessage || \
1350  ( ( localMessage == MESSAGE_GETATTRIBUTE_S && \
1351  ( ( msgData->data == NULL && msgData->length == 0 ) || \
1352  ( msgData->data != NULL && \
1353  msgData->length >= 1 && \
1354  msgData->length < MAX_INTLENGTH ) ) ) || \
1355  ( localMessage == MESSAGE_SETATTRIBUTE_S && \
1356  msgData->data != NULL && \
1357  ( ( msgData->length > 0 && \
1358  msgData->length < MAX_INTLENGTH_SHORT ) || \
1359  messageValue == CRYPT_IATTRIBUTE_ENTROPY ) ) ) );
1360 
1361  /* Must be a string value */
1362  if( localMessage != MESSAGE_GETATTRIBUTE_S && \
1363  localMessage != MESSAGE_SETATTRIBUTE_S )
1364  return( CRYPT_ARGERROR_VALUE );
1365 
1366  /* If we're sending the data back to the caller, the only thing
1367  that we can check is the presence of a writeable output
1368  buffer. We return a string arg error for both the buffer and
1369  length, since the length isn't explicitly specified by an
1370  external caller */
1371  if( localMessage == MESSAGE_GETATTRIBUTE_S )
1372  {
1373  if( !( ( msgData->data == NULL && msgData->length == 0 ) || \
1374  ( msgData->length > 0 && \
1375  isWritePtr( msgData->data, msgData->length ) ) ) )
1376  return( CRYPT_ARGERROR_STR1 );
1377  break;
1378  }
1379 
1380  /* Inner precondition: We're sending data to the object */
1381  REQUIRES( localMessage == MESSAGE_SETATTRIBUTE_S );
1382 
1383  /* Make sure that the string length is within the allowed
1384  range */
1385  if( isSpecialRange( attributeACL ) )
1386  {
1387  if( !checkAttributeRangeSpecial( \
1388  getSpecialRangeType( attributeACL ),
1389  getSpecialRangeInfo( attributeACL ),
1390  msgData->length ) )
1391  return( CRYPT_ARGERROR_NUM1 );
1392  }
1393  else
1394  {
1395  if( attributeACL->valueType == ATTRIBUTE_VALUE_WCSTRING )
1396  {
1397  if( !checkAttributeRangeWidechar( msgData->data,
1398  msgData->length,
1399  attributeACL->lowRange,
1400  attributeACL->highRange ) )
1401  return( CRYPT_ARGERROR_NUM1 );
1402  }
1403  else
1404  {
1405  if( msgData->length < attributeACL->lowRange || \
1406  msgData->length > attributeACL->highRange )
1407  return( CRYPT_ARGERROR_NUM1 );
1408  }
1409  }
1410  if( msgData->length > 0 && \
1411  !isReadPtr( msgData->data, msgData->length ) )
1412  return( CRYPT_ARGERROR_STR1 );
1413  break;
1414  }
1415 
1416  case ATTRIBUTE_VALUE_TIME:
1417  {
1419 
1420  /* Inner precondition: If it's an internal message then it must
1421  be a string value corresponding to a time_t */
1422  assert( isReadPtr( messageDataPtr, sizeof( MESSAGE_DATA ) ) );
1423  assert( !isInternalMessage || \
1424  ( ( localMessage == MESSAGE_GETATTRIBUTE_S || \
1425  localMessage == MESSAGE_SETATTRIBUTE_S ) && \
1426  isReadPtr( msgData->data, msgData->length ) && \
1427  msgData->length == sizeof( time_t ) ) );
1428 
1429  REQUIRES( !isInternalMessage || \
1430  ( ( localMessage == MESSAGE_GETATTRIBUTE_S || \
1431  localMessage == MESSAGE_SETATTRIBUTE_S ) && \
1432  msgData->data != NULL && \
1433  msgData->length == sizeof( time_t ) ) );
1434 
1435  /* Must be a string value */
1436  if( localMessage != MESSAGE_GETATTRIBUTE_S && \
1437  localMessage != MESSAGE_SETATTRIBUTE_S )
1438  return( CRYPT_ARGERROR_VALUE );
1439 
1440  /* If we're sending the data back to the caller, the only thing
1441  that we can check is the presence of a writeable output
1442  buffer. We return a string arg error for both the buffer and
1443  length, since the length isn't explicitly specified by an
1444  external caller */
1445  if( localMessage == MESSAGE_GETATTRIBUTE_S )
1446  {
1447  if( !( ( msgData->data == NULL && msgData->length == 0 ) || \
1448  ( msgData->length > 0 && \
1449  isWritePtr( msgData->data, msgData->length ) ) ) )
1450  return( CRYPT_ARGERROR_STR1 );
1451  break;
1452  }
1453 
1454  /* If we're sending the data back to the caller, we can't check
1455  it yet */
1456  if( localMessage == MESSAGE_GETATTRIBUTE_S )
1457  break;
1458 
1459  /* Inner precondition: We're sending data to the object */
1460  REQUIRES( localMessage == MESSAGE_SETATTRIBUTE_S );
1461 
1462  /* Must contain a time_t in a sensible range */
1463  if( !isReadPtrConst( msgData->data, sizeof( time_t ) ) || \
1464  *( ( time_t * ) msgData->data ) <= MIN_TIME_VALUE )
1465  return( CRYPT_ARGERROR_STR1 );
1466  if( msgData->length != sizeof( time_t ) )
1467  return( CRYPT_ARGERROR_NUM1 );
1468  break;
1469  }
1470 
1472  {
1473  int iterationCount = 0;
1474 
1475  /* It's an ACL with an object-subtype-specific sub-ACL, find the
1476  precise ACL for this object subtype */
1477  for( attributeACL = getSpecialRangeInfo( attributeACL );
1478  attributeACL->valueType != ATTRIBUTE_VALUE_NONE && \
1479  iterationCount++ < FAILSAFE_ITERATIONS_MED;
1480  attributeACL++ )
1481  {
1482  if( isValidSubtype( attributeACL->subTypeA, subType ) || \
1483  isValidSubtype( attributeACL->subTypeB, subType ) || \
1484  isValidSubtype( attributeACL->subTypeC, subType ) )
1485  break;
1486  }
1487  ENSURES( iterationCount < FAILSAFE_ITERATIONS_MED );
1488  ENSURES( attributeACL->valueType != ATTRIBUTE_VALUE_NONE );
1489 
1490  /* Recursively check the message against the sub-ACL */
1491  return( preDispatchCheckAttributeAccess( objectHandle, message,
1492  messageDataPtr, messageValue, attributeACL ) );
1493  }
1494 
1495  default:
1496  retIntError();
1497  }
1498 
1499  return( CRYPT_OK );
1500  }
1501 
1502 /* It's a compare message, make sure that the parameters are OK */
1503 
1504 CHECK_RETVAL \
1505 int preDispatchCheckCompareParam( IN_HANDLE const int objectHandle,
1506  IN_MESSAGE const MESSAGE_TYPE message,
1507  const void *messageDataPtr,
1508  IN_ENUM( MESSAGE_COMPARE ) const int messageValue,
1509  STDC_UNUSED const void *dummy )
1510  {
1511  const OBJECT_INFO *objectTable = krnlData->objectTable;
1512  const OBJECT_INFO *objectInfoPtr = &objectTable[ objectHandle ];
1513  const COMPARE_ACL *compareACL = NULL;
1514 
1515  /* Precondition: It's a valid compare message type */
1516  REQUIRES( isValidMessage( message & MESSAGE_MASK ) );
1517  REQUIRES( fullObjectCheck( objectHandle, message ) );
1518  REQUIRES( messageValue > MESSAGE_COMPARE_NONE && \
1519  messageValue < MESSAGE_COMPARE_LAST );
1520 
1521  /* Find the appropriate ACL for this compare type */
1522  if( messageValue > MESSAGE_COMPARE_NONE && \
1523  messageValue < MESSAGE_COMPARE_LAST )
1524  compareACL = &compareACLTbl[ messageValue - 1 ];
1525  ENSURES( compareACL != NULL );
1526 
1527  /* Inner precondition: We have the correct ACL, and the full object
1528  check has been performed by the kernel */
1529  REQUIRES( compareACL->compareType == messageValue );
1530 
1531  /* Check the message target. The full object check has already been
1532  performed by the message dispatcher so all we need to check is the
1533  compare-specific subtype. We throw an exception if we find an
1534  invalid parameter, both because this is an internal message and this
1535  situation shouldn't occur, and because an error return from a compare
1536  message is perfectly valid (it denotes a non-match) so parameter
1537  errors won't otherwise be caught by the caller */
1538  ENSURES( isValidSubtype( compareACL->objectACL.subTypeA, \
1539  objectInfoPtr->subType ) );
1540  if( ( compareACL->objectACL.flags & ACL_FLAG_STATE_MASK ) && \
1541  !checkObjectState( compareACL->objectACL.flags, objectHandle ) )
1542  retIntError();
1543 
1544  /* Check the message parameters. We throw an exception if we find an
1545  invalid parameter for the reason given above */
1546  if( paramInfo( compareACL, 0 ).valueType == PARAM_VALUE_OBJECT )
1547  {
1548  STDC_UNUSED \
1549  const CRYPT_HANDLE iCryptHandle = *( ( CRYPT_HANDLE * ) messageDataPtr );
1550 
1551  REQUIRES( fullObjectCheck( iCryptHandle, message ) && \
1552  isSameOwningObject( objectHandle, iCryptHandle ) );
1553  REQUIRES( checkParamObject( paramInfo( compareACL, 0 ), \
1554  iCryptHandle ) );
1555  }
1556  else
1557  {
1558  STDC_UNUSED \
1560 
1561  REQUIRES( checkParamString( paramInfo( compareACL, 0 ),
1562  msgData->data, msgData->length ) );
1563  }
1564 
1565  /* Postconditions: The compare parameters are valid, either an object
1566  handle or a string value at least as big as a minimal-length DN */
1567  assert( ( messageValue == MESSAGE_COMPARE_CERTOBJ && \
1568  isValidHandle( *( ( CRYPT_HANDLE * ) messageDataPtr ) ) ) || \
1569  ( messageValue != MESSAGE_COMPARE_CERTOBJ && \
1570  isReadPtr( messageDataPtr, sizeof( MESSAGE_DATA ) ) && \
1571  ( ( MESSAGE_DATA * ) messageDataPtr )->length >= 2 && \
1572  isReadPtr( ( ( MESSAGE_DATA * ) messageDataPtr )->data, \
1573  ( ( MESSAGE_DATA * ) messageDataPtr )->length ) ) );
1574 
1575  ENSURES( ( messageValue == MESSAGE_COMPARE_CERTOBJ && \
1576  isValidHandle( *( ( CRYPT_HANDLE * ) messageDataPtr ) ) ) || \
1577  ( messageValue != MESSAGE_COMPARE_CERTOBJ && \
1578  messageDataPtr != NULL && \
1579  ( ( ( MESSAGE_DATA * ) messageDataPtr )->data != NULL && \
1580  ( ( MESSAGE_DATA * ) messageDataPtr )->length >= 2 && \
1581  ( ( MESSAGE_DATA * ) messageDataPtr )->length < MAX_INTLENGTH ) ) );
1582 
1583  return( CRYPT_OK );
1584  }
1585 
1586 /* It's a check message, make sure that the parameters are OK */
1587 
1588 CHECK_RETVAL \
1589 int preDispatchCheckCheckParam( IN_HANDLE const int objectHandle,
1590  IN_MESSAGE const MESSAGE_TYPE message,
1591  STDC_UNUSED const void *dummy1,
1592  IN_ENUM( MESSAGE_CHECK ) const int messageValue,
1593  STDC_UNUSED const void *dummy2 )
1594  {
1595  const OBJECT_INFO *objectTable = krnlData->objectTable;
1596  const OBJECT_INFO *objectInfoPtr = &objectTable[ objectHandle ];
1597  const CHECK_ACL *checkACL = NULL;
1598  int status;
1599 
1600  /* Precondition: It's a valid check message type */
1601  REQUIRES( isValidMessage( message & MESSAGE_MASK ) );
1602  REQUIRES( fullObjectCheck( objectHandle, message ) );
1603  REQUIRES( messageValue > MESSAGE_CHECK_NONE && \
1604  messageValue < MESSAGE_CHECK_LAST );
1605 
1606  /* Find the ACL information for the message type */
1607  status = findCheckACL( messageValue, objectInfoPtr->type,
1608  &checkACL, NULL );
1609  if( cryptStatusError( status ) )
1610  return( status );
1611 
1612  /* Check the message target. The full object check has already been
1613  performed by the message dispatcher so all we need to check is the
1614  compare-specific subtype */
1615  if( !( isValidSubtype( checkACL->objectACL.subTypeA, \
1616  objectInfoPtr->subType ) || \
1617  isValidSubtype( checkACL->objectACL.subTypeB, \
1618  objectInfoPtr->subType ) ) )
1619  return( CRYPT_ARGERROR_OBJECT );
1620  if( ( checkACL->objectACL.flags & ACL_FLAG_STATE_MASK ) && \
1621  !checkObjectState( checkACL->objectACL.flags, objectHandle ) )
1622  {
1623  /* The object is in the wrong state, meaning that it's inited when
1624  it shouldn't be or not inited when it should be, return a more
1625  specific error message */
1626  return( isInHighState( objectHandle ) ? \
1628  }
1629 
1630  /* Make sure that the object's usage count is still valid. The usage
1631  count is a type of meta-capability that overrides all other
1632  capabilities in that an object with an expired usage count isn't
1633  valid for anything no matter what the available capabilities are */
1634  if( objectInfoPtr->usageCount != CRYPT_UNUSED && \
1635  objectInfoPtr->usageCount <= 0 )
1636  return( CRYPT_ARGERROR_OBJECT );
1637 
1638  /* If this is a context and there's an action associated with this
1639  check, make sure that the requested action is permitted for this
1640  object */
1641  if( objectInfoPtr->type == OBJECT_TYPE_CONTEXT && \
1642  checkACL->actionType != MESSAGE_NONE )
1643  {
1644  const BOOLEAN isInternalMessage = isInternalMessage( message ) ? \
1645  TRUE : FALSE;
1646 
1647  /* Check that the action is permitted. We convert the return status
1648  to a CRYPT_ERROR_NOTAVAIL, which makes more sense than a generic
1649  object error */
1650  status = checkActionPermitted( objectInfoPtr, isInternalMessage ? \
1651  MKINTERNAL( checkACL->actionType ) : \
1652  checkACL->actionType );
1653  if( cryptStatusError( status ) )
1654  return( CRYPT_ERROR_NOTAVAIL );
1655  }
1656 
1657  /* Postconditions: The object being checked is valid */
1658  ENSURES( fullObjectCheck( objectHandle, message ) && \
1659  ( isValidSubtype( checkACL->objectACL.subTypeA, \
1660  objectInfoPtr->subType ) || \
1661  isValidSubtype( checkACL->objectACL.subTypeB, \
1662  objectInfoPtr->subType ) ) );
1663 
1664  return( CRYPT_OK );
1665  }
1666 
1667 /* It's a context action message, check the access conditions for the object */
1668 
1669 CHECK_RETVAL \
1670 int preDispatchCheckActionAccess( IN_HANDLE const int objectHandle,
1671  IN_MESSAGE const MESSAGE_TYPE message,
1672  STDC_UNUSED const void *dummy1,
1673  STDC_UNUSED const int dummy2,
1674  STDC_UNUSED const void *dummy3 )
1675  {
1676  const OBJECT_INFO *objectInfoPtr = &krnlData->objectTable[ objectHandle ];
1677  const MESSAGE_TYPE localMessage = message & MESSAGE_MASK;
1678  int status;
1679 
1680  /* Precondition: It's a valid access */
1681  REQUIRES( isValidObject( objectHandle ) );
1682  REQUIRES( isActionMessage( localMessage ) );
1683 
1684  /* If the object is in the low state, it can't be used for any action */
1685  if( !isInHighState( objectHandle ) )
1686  return( CRYPT_ERROR_NOTINITED );
1687 
1688  /* If the object is in the high state, it can't receive another message
1689  of the kind that causes the state change */
1690  if( localMessage == MESSAGE_CTX_GENKEY )
1691  return( CRYPT_ERROR_INITED );
1692 
1693  /* If there's a usage count set for the object and it's gone to zero, it
1694  can't be used any more */
1695  if( objectInfoPtr->usageCount != CRYPT_UNUSED && \
1696  objectInfoPtr->usageCount <= 0 )
1697  return( CRYPT_ERROR_PERMISSION );
1698 
1699  /* Inner precondition: Object is in the high state and can process the
1700  action message */
1701  REQUIRES( isInHighState( objectHandle ) );
1702  REQUIRES( objectInfoPtr->usageCount == CRYPT_UNUSED || \
1703  objectInfoPtr->usageCount > 0 );
1704 
1705  /* Check that the requested action is permitted for this object */
1706  status = checkActionPermitted( objectInfoPtr, message );
1707  if( cryptStatusError( status ) )
1708  return( status );
1709 
1710  /* Postcondition */
1711  ENSURES( localMessage != MESSAGE_CTX_GENKEY );
1712  ENSURES( isInHighState( objectHandle ) );
1713  ENSURES( objectInfoPtr->usageCount == CRYPT_UNUSED || \
1714  objectInfoPtr->usageCount > 0 );
1716  checkActionPermitted( objectInfoPtr, message ) ) );
1717 
1718  return( CRYPT_OK );
1719  }
1720 
1721 /* If it's a state change trigger message, make sure that the object isn't
1722  already in the high state */
1723 
1724 CHECK_RETVAL \
1725 int preDispatchCheckState( IN_HANDLE const int objectHandle,
1726  IN_MESSAGE const MESSAGE_TYPE message,
1727  STDC_UNUSED const void *dummy1,
1728  STDC_UNUSED const int dummy2,
1729  STDC_UNUSED const void *dummy3 )
1730  {
1731  const MESSAGE_TYPE localMessage = message & MESSAGE_MASK;
1732 
1733  /* Precondition: It's a valid access */
1734  REQUIRES( isValidObject( objectHandle ) );
1735  REQUIRES( isValidMessage( localMessage ) );
1736 
1737  if( isInHighState( objectHandle ) )
1738  return( CRYPT_ERROR_PERMISSION );
1739 
1740  /* If it's a keygen message, perform a secondary check to ensure that key
1741  generation is permitted for this object */
1742  if( localMessage == MESSAGE_CTX_GENKEY )
1743  {
1744  int status;
1745 
1746  /* Check that the requested action is permitted for this object */
1747  status = checkActionPermitted( &krnlData->objectTable[ objectHandle ],
1748  message );
1749  if( cryptStatusError( status ) )
1750  return( status );
1751  }
1752 
1753  /* Postcondition: Object is in the low state so a state change message
1754  is valid */
1755  ENSURES( !isInHighState( objectHandle ) );
1756 
1757  return( CRYPT_OK );
1758  }
1759 
1760 /* Check the access conditions for a message containing an optional handle
1761  as the message parameter */
1762 
1763 CHECK_RETVAL \
1764 int preDispatchCheckParamHandleOpt( IN_HANDLE const int objectHandle,
1765  IN_MESSAGE const MESSAGE_TYPE message,
1766  STDC_UNUSED const void *dummy1,
1767  const int messageValue,
1768  IN TYPECAST( MESSAGE_ACL * ) const void *auxInfo )
1769  {
1770  const MESSAGE_ACL *messageACL = ( MESSAGE_ACL * ) auxInfo;
1771  const OBJECT_ACL *objectACL = &messageACL->objectACL;
1772  const OBJECT_INFO *objectTable = krnlData->objectTable;
1773  int subType;
1774 
1775  assert( isReadPtr( messageACL, sizeof( MESSAGE_ACL ) ) );
1776 
1777  /* Preconditions: The access is valid and we've been supplied a valid
1778  check ACL */
1779  REQUIRES( isValidObject( objectHandle ) );
1780  REQUIRES( isValidMessage( message & MESSAGE_MASK ) );
1781  REQUIRES( messageACL->type == ( message & MESSAGE_MASK ) );
1782 
1783  /* If the object parameter is CRYPT_UNUSED (for example for a self-signed
1784  certificate), we're OK */
1785  if( messageValue == CRYPT_UNUSED )
1786  return( CRYPT_OK );
1787 
1788  /* Make sure that the object parameter is valid and accessible */
1789  if( !fullObjectCheck( messageValue, message ) || \
1790  !isSameOwningObject( objectHandle, messageValue ) )
1791  return( CRYPT_ARGERROR_VALUE );
1792 
1793  /* Make sure that the object parameter subtype is correct */
1794  subType = objectTable[ messageValue ].subType;
1795  if( !isValidSubtype( objectACL->subTypeA, subType ) && \
1796  !isValidSubtype( objectACL->subTypeB, subType ) && \
1797  !isValidSubtype( objectACL->subTypeC, subType ) )
1798  return( CRYPT_ARGERROR_VALUE );
1799 
1800  /* Postcondition: Object parameter is valid, accessible, and of the
1801  correct type */
1802  ENSURES( fullObjectCheck( messageValue, message ) && \
1803  isSameOwningObject( objectHandle, messageValue ) );
1804  ENSURES( isValidSubtype( objectACL->subTypeA, subType ) || \
1805  isValidSubtype( objectACL->subTypeB, subType ) || \
1806  isValidSubtype( objectACL->subTypeC, subType ) );
1807 
1808  return( CRYPT_OK );
1809  }
1810 
1811 /* Perform a combined check of the object and the handle */
1812 
1813 CHECK_RETVAL \
1814 int preDispatchCheckStateParamHandle( IN_HANDLE const int objectHandle,
1815  IN_MESSAGE const MESSAGE_TYPE message,
1816  STDC_UNUSED const void *dummy1,
1817  const int messageValue,
1818  IN TYPECAST( MESSAGE_ACL * ) \
1819  const void *auxInfo )
1820  {
1821  const MESSAGE_ACL *messageACL = ( MESSAGE_ACL * ) auxInfo;
1822  const OBJECT_ACL *objectACL = &messageACL->objectACL;
1823  const OBJECT_INFO *objectTable = krnlData->objectTable;
1824  int subType;
1825 
1826  assert( isReadPtr( messageACL, sizeof( MESSAGE_ACL ) ) );
1827 
1828  /* Preconditions: The access is valid and we've been supplied a valid
1829  check ACL */
1830  REQUIRES( isValidMessage( message & MESSAGE_MASK ) );
1831  REQUIRES( fullObjectCheck( objectHandle, message ) );
1832  REQUIRES( messageACL->type == ( message & MESSAGE_MASK ) );
1833 
1834  if( isInHighState( objectHandle ) )
1835  return( CRYPT_ERROR_PERMISSION );
1836 
1837  /* Make sure that the object parameter is valid and accessible */
1838  if( !fullObjectCheck( messageValue, message ) || \
1839  !isSameOwningObject( objectHandle, messageValue ) )
1840  return( CRYPT_ARGERROR_VALUE );
1841 
1842  /* Make sure that the object parameter subtype is correct */
1843  subType = objectTable[ messageValue ].subType;
1844  if( !isValidSubtype( objectACL->subTypeA, subType ) && \
1845  !isValidSubtype( objectACL->subTypeB, subType ) && \
1846  !isValidSubtype( objectACL->subTypeC, subType ) )
1847  return( CRYPT_ARGERROR_VALUE );
1848 
1849  /* Postcondition: Object is in the low state so a state change message
1850  is valid and the object parameter is valid, accessible, and of the
1851  correct type */
1852  ENSURES( !isInHighState( objectHandle ) );
1853  ENSURES( fullObjectCheck( messageValue, message ) && \
1854  isSameOwningObject( objectHandle, messageValue ) );
1855  ENSURES( isValidSubtype( objectACL->subTypeA, subType ) || \
1856  isValidSubtype( objectACL->subTypeB, subType ) || \
1857  isValidSubtype( objectACL->subTypeC, subType ) );
1858 
1859  return( CRYPT_OK );
1860  }
1861 
1862 /* We're exporting a certificate, make sure that the format is valid for
1863  this certificate type */
1864 
1865 CHECK_RETVAL \
1866 int preDispatchCheckExportAccess( IN_HANDLE const int objectHandle,
1867  IN_MESSAGE const MESSAGE_TYPE message,
1868  const void *messageDataPtr,
1869  IN_ENUM( CRYPT_CERTFORMAT ) const int messageValue,
1870  STDC_UNUSED const void *dummy2 )
1871  {
1872  const ATTRIBUTE_ACL *formatACL;
1873  int i;
1874 
1875  /* Precondition */
1876  REQUIRES( isValidObject( objectHandle ) );
1877  REQUIRES( isValidMessage( message & MESSAGE_MASK ) );
1878  REQUIRES( messageDataPtr != NULL );
1879  REQUIRES( messageValue > CRYPT_CERTFORMAT_NONE && \
1880  messageValue < CRYPT_CERTFORMAT_LAST );
1881 
1882  /* Make sure that the export format is valid */
1883  if( messageValue <= CRYPT_CERTFORMAT_NONE || \
1884  messageValue >= CRYPT_CERTFORMAT_LAST )
1885  return( CRYPT_ARGERROR_VALUE );
1886 
1887  /* Find the appropriate ACL for this export type */
1888  for( i = 0; formatPseudoACL[ i ].attribute != messageValue &&
1889  formatPseudoACL[ i ].attribute != CRYPT_CERTFORMAT_NONE && \
1890  i < FAILSAFE_ARRAYSIZE( formatPseudoACL, ATTRIBUTE_ACL_ALT );
1891  i++ );
1892  ENSURES( i < FAILSAFE_ARRAYSIZE( formatPseudoACL, ATTRIBUTE_ACL_ALT ) );
1893  ENSURES( formatPseudoACL[ i ].attribute != CRYPT_CERTFORMAT_NONE );
1894 
1895  /* The easiest way to handle this check is to use an ACL, treating the
1896  format type as a pseudo-attribute type */
1897  formatACL = ( ATTRIBUTE_ACL * ) &formatPseudoACL[ i ];
1898  assert( formatACL->attribute == messageValue );
1899  /* Only in debug build, see comment in attr_acl.c */
1900 
1901  return( preDispatchCheckAttributeAccess( objectHandle,
1902  isInternalMessage( message ) ? \
1904  messageDataPtr, messageValue, formatACL ) );
1905  }
1906 
1907 /* It's data being pushed or popped, make sure that it's a valid data
1908  quantity */
1909 
1911 int preDispatchCheckData( IN_HANDLE const int objectHandle,
1912  IN_MESSAGE const MESSAGE_TYPE message,
1913  IN_BUFFER_C( sizeof( MESSAGE_DATA ) ) \
1914  const void *messageDataPtr,
1915  STDC_UNUSED const int dummy1,
1916  STDC_UNUSED const void *dummy2 )
1917  {
1918  const MESSAGE_TYPE localMessage = message & MESSAGE_MASK;
1920 
1921  assert( isReadPtr( messageDataPtr, sizeof( MESSAGE_DATA ) ) );
1922 
1923  /* Precondition */
1924  REQUIRES( isValidObject( objectHandle ) );
1925  REQUIRES( isValidMessage( localMessage ) );
1926 
1927  /* Make sure that it's either a flush (buffer = NULL, length = 0)
1928  or valid data */
1929  if( msgData->data == NULL )
1930  {
1931  if( localMessage != MESSAGE_ENV_PUSHDATA )
1932  return( CRYPT_ARGERROR_STR1 );
1933  if( msgData->length != 0 )
1934  return( CRYPT_ARGERROR_NUM1 );
1935  }
1936  else
1937  {
1938  if( msgData->length <= 0 )
1939  return( CRYPT_ARGERROR_NUM1 );
1940  if( !isReadPtr( msgData->data, msgData->length ) )
1941  return( CRYPT_ARGERROR_STR1 );
1942  }
1943 
1944  /* Postcondition: It's a flush or it's valid data */
1945  ENSURES( ( localMessage == MESSAGE_ENV_PUSHDATA && \
1946  msgData->data == NULL && msgData->length == 0 ) || \
1947  ( msgData->data != NULL && msgData->length > 0 ) );
1948 
1949  return( CRYPT_OK );
1950  }
1951 
1952 /* We're creating a new object, make sure that the create parameters are
1953  valid and set the new object's owner to the owner of the object that it's
1954  being created through */
1955 
1956 CHECK_RETVAL STDC_NONNULL_ARG( ( 3 ) ) \
1957 int preDispatchCheckCreate( IN_HANDLE const int objectHandle,
1958  IN_MESSAGE const MESSAGE_TYPE message,
1959  IN_BUFFER_C( sizeof( MESSAGE_CREATEOBJECT_INFO ) ) \
1960  const void *messageDataPtr,
1961  IN_ENUM( OBJECT ) const int messageValue,
1962  STDC_UNUSED const void *dummy )
1963  {
1964  const OBJECT_INFO *objectTable = krnlData->objectTable;
1965  const MESSAGE_TYPE localMessage = message & MESSAGE_MASK;
1966  const CREATE_ACL *createACL = \
1967  ( localMessage == MESSAGE_DEV_CREATEOBJECT ) ? \
1968  createObjectACL : createObjectIndirectACL;
1969  const int createAclSize = \
1970  ( localMessage == MESSAGE_DEV_CREATEOBJECT ) ? \
1971  FAILSAFE_ARRAYSIZE( createObjectACL, CREATE_ACL ) : \
1972  FAILSAFE_ARRAYSIZE( createObjectIndirectACL, CREATE_ACL );
1973  MESSAGE_CREATEOBJECT_INFO *createInfo = \
1974  ( MESSAGE_CREATEOBJECT_INFO * ) messageDataPtr;
1975  int i;
1976 
1977  assert( isReadPtr( messageDataPtr, sizeof( MESSAGE_CREATEOBJECT_INFO ) ) );
1978 
1979  /* Precondition */
1980  REQUIRES( fullObjectCheck( objectHandle, message ) && \
1981  objectTable[ objectHandle ].type == OBJECT_TYPE_DEVICE );
1982  REQUIRES( localMessage == MESSAGE_DEV_CREATEOBJECT || \
1983  localMessage == MESSAGE_DEV_CREATEOBJECT_INDIRECT );
1984  REQUIRES( isValidType( messageValue ) );
1985  REQUIRES( createInfo->cryptHandle == CRYPT_ERROR );
1986  REQUIRES( createInfo->cryptOwner == CRYPT_ERROR || \
1987  createInfo->cryptOwner == DEFAULTUSER_OBJECT_HANDLE || \
1988  isHandleRangeValid( createInfo->cryptOwner ) );
1989 
1990  /* Find the appropriate ACL for this object create type */
1991  for( i = 0; i < createAclSize && \
1992  createACL[ i ].type != messageValue &&
1993  createACL[ i ].type != CRYPT_CERTFORMAT_NONE; i++ );
1994  ENSURES( i < createAclSize );
1995  ENSURES( createACL[ i ].type != OBJECT_TYPE_NONE );
1996  createACL = &createACL[ i ];
1997 
1998  /* Check whether this object subtype requires special handling and if it
1999  does switch to the alternative ACL. The default value for the
2000  entries in the exceptions list is 0, but no valid exceptionally
2001  processed sub-type has this value (which corresponds to
2002  CRYPT_something_NONE) so we can never inadvertently match a valid
2003  type. We do however have to check for a nonzero subtype argument
2004  since for indirect object creates the subtype arg.can be zero if type
2005  autodetection is being used */
2006  if( createInfo->arg1 != 0 && \
2007  ( createACL->exceptions[ 0 ] == createInfo->arg1 || \
2008  createACL->exceptions[ 1 ] == createInfo->arg1 ) )
2009  createACL = createACL->exceptionACL;
2010 
2011  /* Make sure that the subtype is valid for this object type */
2012  if( !checkParamNumeric( paramInfo( createACL, 0 ), createInfo->arg1 ) )
2013  return( CRYPT_ARGERROR_NUM1 );
2014 
2015  /* Make sure that any additional numeric argument is valid */
2016  ENSURES( checkParamNumeric( paramInfo( createACL, 1 ),
2017  createInfo->arg2 ) );
2018 
2019  /* Make sure that any string arguments are valid */
2020  if( !checkParamString( paramInfo( createACL, 2 ),
2021  createInfo->strArg1, createInfo->strArgLen1 ) )
2022  return( CRYPT_ARGERROR_STR1 );
2023  if( !checkParamString( paramInfo( createACL, 3 ),
2024  createInfo->strArg2, createInfo->strArgLen2 ) )
2025  return( CRYPT_ARGERROR_STR2 );
2026 
2027  /* If there's no object owner explicitly set, set the new object's owner
2028  to the owner of the object that it's being created through. If it's
2029  being created through the system device object (which has no owner)
2030  we set the owner to the default user object */
2031  if( createInfo->cryptOwner == CRYPT_ERROR )
2032  {
2033  if( objectHandle == SYSTEM_OBJECT_HANDLE )
2034  createInfo->cryptOwner = DEFAULTUSER_OBJECT_HANDLE;
2035  else
2036  {
2037  const int ownerObject = objectTable[ objectHandle ].owner;
2038 
2039  /* Inner precondition: The owner is a valid user object */
2040  REQUIRES( isValidObject( ownerObject ) && \
2041  objectTable[ ownerObject ].type == OBJECT_TYPE_USER );
2042 
2043  createInfo->cryptOwner = ownerObject;
2044  }
2045  }
2046 
2047  /* Postcondition: The new object's owner will be the user object it's
2048  being created through or the default user if it's being done via the
2049  system object */
2050  ENSURES( ( objectHandle == SYSTEM_OBJECT_HANDLE && \
2051  createInfo->cryptOwner == DEFAULTUSER_OBJECT_HANDLE ) || \
2052  ( objectHandle != SYSTEM_OBJECT_HANDLE && \
2053  createInfo->cryptOwner == objectTable[ objectHandle ].owner ) );
2054 
2055  return( CRYPT_OK );
2056  }
2057 
2058 /* It's a user management message, make sure that it's valid */
2059 
2060 CHECK_RETVAL \
2061 int preDispatchCheckUserMgmtAccess( IN_HANDLE const int objectHandle,
2062  IN_MESSAGE const MESSAGE_TYPE message,
2063  STDC_UNUSED const void *dummy1,
2064  IN_ENUM( MESSAGE_USERMGMT ) const int messageValue,
2065  STDC_UNUSED const void *dummy2 )
2066  {
2067  STDC_UNUSED \
2068  const OBJECT_INFO *objectTable = krnlData->objectTable;
2069  STDC_UNUSED \
2070  const MESSAGE_TYPE localMessage = message & MESSAGE_MASK;
2071 
2072  REQUIRES( fullObjectCheck( objectHandle, message ) && \
2073  objectTable[ objectHandle ].type == OBJECT_TYPE_USER );
2074  REQUIRES( localMessage == MESSAGE_USER_USERMGMT );
2075  REQUIRES( messageValue > MESSAGE_USERMGMT_NONE && \
2076  messageValue < MESSAGE_USERMGMT_LAST );
2077 
2078  /* At the moment with only minimal user management available it's
2079  easiest to hardcode the checks */
2080  switch( messageValue )
2081  {
2083  return( CRYPT_OK );
2084  }
2085 
2086  retIntError();
2087  }
2088 
2089 /* It's a trust management message, make sure that it's valid */
2090 
2091 CHECK_RETVAL \
2092 int preDispatchCheckTrustMgmtAccess( IN_HANDLE const int objectHandle,
2093  IN_MESSAGE const MESSAGE_TYPE message,
2094  const void *messageDataPtr,
2095  STDC_UNUSED const int messageValue,
2096  STDC_UNUSED const void *dummy )
2097  {
2098  static const OBJECT_ACL FAR_BSS objectTrustedCertificate = {
2101  static const ATTRIBUTE_ACL FAR_BSS trustMgmtPseudoACL[] = {
2102  MKACL_O(
2103  MESSAGE_TRUSTMGMT_CHECK, /* Generic placeholder */
2105  ROUTE( OBJECT_TYPE_USER ), &objectTrustedCertificate )
2106  };
2107  STDC_UNUSED \
2108  const OBJECT_INFO *objectTable = krnlData->objectTable;
2109  STDC_UNUSED \
2110  const MESSAGE_TYPE localMessage = message & MESSAGE_MASK;
2111 
2112  assert( ( messageValue == MESSAGE_TRUSTMGMT_GETISSUER && \
2113  isWritePtr( ( void * ) messageDataPtr, \
2114  sizeof( CRYPT_HANDLE ) ) ) || \
2115  ( isReadPtr( messageDataPtr, sizeof( CRYPT_HANDLE ) ) ) );
2116 
2117  REQUIRES( fullObjectCheck( objectHandle, message ) && \
2118  objectTable[ objectHandle ].type == OBJECT_TYPE_USER );
2119  REQUIRES( localMessage == MESSAGE_USER_TRUSTMGMT );
2120  REQUIRES( messageValue > MESSAGE_TRUSTMGMT_NONE && \
2121  messageValue < MESSAGE_TRUSTMGMT_LAST );
2122 
2123  /* The easiest way to handle this check is to use an ACL, treating the
2124  trust management operation type as a pseudo-attribute type */
2125  return( preDispatchCheckAttributeAccess( objectHandle,
2126  isInternalMessage( message ) ? \
2128  messageDataPtr, MESSAGE_TRUSTMGMT_CHECK,
2129  trustMgmtPseudoACL ) );
2130  }
2131 
2132 /****************************************************************************
2133 * *
2134 * Message Post-Dispatch Handlers *
2135 * *
2136 ****************************************************************************/
2137 
2138 /* If we're fetching or creating an object, it won't be visible to an
2139  outside caller. If it's an external message, we have to make the object
2140  externally visible before we return it */
2141 
2142 CHECK_RETVAL \
2144  IN_MESSAGE const MESSAGE_TYPE message,
2145  const void *messageDataPtr,
2146  const int messageValue,
2147  const void *auxInfo )
2148  {
2149  const MESSAGE_TYPE localMessage = message & MESSAGE_MASK;
2150  const BOOLEAN isInternalMessage = isInternalMessage( message ) ? \
2151  TRUE : FALSE;
2152  CRYPT_HANDLE objectHandle;
2153  int status;
2154 
2155  /* Preconditions */
2156  REQUIRES( localMessage == MESSAGE_GETATTRIBUTE || \
2157  localMessage == MESSAGE_DEV_CREATEOBJECT || \
2158  localMessage == MESSAGE_DEV_CREATEOBJECT_INDIRECT || \
2159  localMessage == MESSAGE_KEY_GETKEY || \
2160  localMessage == MESSAGE_KEY_GETNEXTCERT || \
2161  localMessage == MESSAGE_KEY_CERTMGMT );
2162  REQUIRES( messageDataPtr != NULL );
2163 
2164  /* If it's an internal message, there are no problems with object
2165  visibility. In addition most messages are internal, so performing
2166  this check before anything else quickly weeds out the majority of
2167  cases */
2168  if( isInternalMessage )
2169  return( CRYPT_OK );
2170 
2171  switch( localMessage )
2172  {
2173  case MESSAGE_GETATTRIBUTE:
2174  {
2175  const ATTRIBUTE_ACL *attributeACL = ( ATTRIBUTE_ACL * ) auxInfo;
2176 
2177  assert( isReadPtr( attributeACL, sizeof( ATTRIBUTE_ACL ) ) );
2178 
2179  /* Inner precondition: Since it's an external message, we must
2180  be reading a standard attribute */
2181  REQUIRES( isAttribute( messageValue ) );
2182  assert( attributeACL->attribute == messageValue );
2183  /* Only in debug build, see comment in attr_acl.c */
2184 
2185  /* If it's not an object attribute read, we're done */
2186  if( attributeACL->valueType == ATTRIBUTE_VALUE_SPECIAL )
2187  {
2188  attributeACL = getSpecialRangeInfo( attributeACL );
2189  assert( isReadPtr( attributeACL, sizeof( ATTRIBUTE_ACL ) ) );
2190  ENSURES( attributeACL != NULL );
2191  }
2192  if( attributeACL->valueType != ATTRIBUTE_VALUE_OBJECT )
2193  return( CRYPT_OK );
2194 
2195  /* Inner precondition: We're reading an object attribute and
2196  sending the response to an external caller */
2197  REQUIRES( attributeACL->valueType == ATTRIBUTE_VALUE_OBJECT );
2198  REQUIRES( isValidObject( *( ( int * ) messageDataPtr ) ) );
2199  REQUIRES( !isInternalMessage );
2200 
2201  objectHandle = *( ( int * ) messageDataPtr );
2202  break;
2203  }
2204 
2207  {
2208  MESSAGE_CREATEOBJECT_INFO *createInfo = \
2209  ( MESSAGE_CREATEOBJECT_INFO * ) messageDataPtr;
2210 
2211  assert( isReadPtr( createInfo, \
2212  sizeof( MESSAGE_CREATEOBJECT_INFO ) ) );
2213 
2214  objectHandle = createInfo->cryptHandle;
2215  break;
2216  }
2217 
2218  case MESSAGE_KEY_GETKEY:
2220  {
2221  MESSAGE_KEYMGMT_INFO *getkeyInfo = \
2222  ( MESSAGE_KEYMGMT_INFO * ) messageDataPtr;
2223 
2224  assert( isReadPtr( getkeyInfo, \
2225  sizeof( MESSAGE_KEYMGMT_INFO ) ) );
2226 
2227  objectHandle = getkeyInfo->cryptHandle;
2228 
2229  ENSURES( isInHighState( objectHandle ) );
2230  break;
2231  }
2232 
2233  case MESSAGE_KEY_CERTMGMT:
2234  {
2235  MESSAGE_CERTMGMT_INFO *certMgmtInfo = \
2236  ( MESSAGE_CERTMGMT_INFO * ) messageDataPtr;
2237 
2238  assert( isReadPtr( certMgmtInfo, \
2239  sizeof( MESSAGE_CERTMGMT_INFO ) ) );
2240 
2241  /* If it's not a certificate management action that can return
2242  an object, there's no object to make visible */
2243  if( messageValue != CRYPT_CERTACTION_ISSUE_CERT && \
2244  messageValue != CRYPT_CERTACTION_CERT_CREATION && \
2245  messageValue != CRYPT_CERTACTION_ISSUE_CRL )
2246  return( CRYPT_OK );
2247 
2248  /* If the caller has indicated that they're not interested in the
2249  newly-created object, it won't be present so we can't make it
2250  externally visible */
2251  if( certMgmtInfo->cryptCert == CRYPT_UNUSED )
2252  return( CRYPT_OK );
2253 
2254  /* Inner precondition: It's an action that can return an object,
2255  and there's an object present */
2256  REQUIRES( messageValue == CRYPT_CERTACTION_ISSUE_CERT || \
2257  messageValue == CRYPT_CERTACTION_CERT_CREATION || \
2258  messageValue == CRYPT_CERTACTION_ISSUE_CRL );
2259  REQUIRES( certMgmtInfo->cryptCert != CRYPT_UNUSED );
2260 
2261  objectHandle = certMgmtInfo->cryptCert;
2262 
2263  ENSURES( isInHighState( objectHandle ) );
2264  break;
2265  }
2266 
2267  default:
2268  retIntError();
2269  }
2270 
2271  /* Postcondition: We've got a valid internal object to make externally
2272  visible */
2273  ENSURES( isValidObject( objectHandle ) && \
2274  isInternalObject( objectHandle ) );
2275 
2276  /* Make the object externally visible. In theory we should make this
2277  attribute read-only, but it's currently still needed in init.c (the
2278  kernel self-test, which checks for internal vs. external
2279  accessibility), keyex.c (to make PGP imported contexts visible),
2280  sign.c (to make CMS signing attributes externally visible), and
2281  cryptapi.c when creating objects (to make them externally visible)
2282  and destroying objects (to make the appear destroyed if a dec-
2283  refcount leaves it still active) */
2284  status = krnlSendMessage( objectHandle, IMESSAGE_SETATTRIBUTE,
2286  CRYPT_IATTRIBUTE_INTERNAL );
2287  if( cryptStatusError( status ) )
2288  return( status );
2289 
2290  /* Postcondition: The object is now externally visible */
2291  ENSURES( isValidObject( objectHandle ) && \
2292  !isInternalObject( objectHandle ) );
2293 
2294  return( CRYPT_OK );
2295  }
2296 
2297 /* If there's a dependent object with a given relationship to the controlling
2298  object, forward the message. In practice the only dependencies are those
2299  of PKC contexts paired with certificates, for which a message sent to one
2300  (e.g. a check message such as "is this suitable for signing?") needs to be
2301  forwarded to the other */
2302 
2303 CHECK_RETVAL \
2305  IN_MESSAGE const MESSAGE_TYPE message,
2306  STDC_UNUSED const void *dummy1,
2307  IN_ENUM( MESSAGE_CHECK ) const int messageValue,
2308  STDC_UNUSED const void *dummy2 )
2309  {
2310  const OBJECT_INFO *objectInfoPtr = &krnlData->objectTable[ objectHandle ];
2311  const int dependentObject = objectInfoPtr->dependentObject;
2312  const OBJECT_TYPE objectType = objectInfoPtr->type;
2313  const OBJECT_TYPE dependentType = isValidObject( dependentObject ) ? \
2314  krnlData->objectTable[ dependentObject ].type : CRYPT_ERROR;
2315  const CHECK_ALT_ACL *checkAltACL;
2316  MESSAGE_CHECK_TYPE localMessageValue = messageValue;
2317  int status;
2318 
2319  /* Precondition: It's an appropriate message type being forwarded to a
2320  dependent object */
2321  REQUIRES( isValidObject( objectHandle ) );
2322  REQUIRES( ( message & MESSAGE_MASK ) == MESSAGE_CHECK );
2323  REQUIRES( messageValue > MESSAGE_CHECK_NONE && \
2324  messageValue < MESSAGE_CHECK_LAST );
2325  REQUIRES( isValidObject( dependentObject ) || \
2326  dependentObject == CRYPT_ERROR );
2327 
2328  /* Find the ACL information for the message type */
2329  status = findCheckACL( messageValue, objectInfoPtr->type, NULL,
2330  &checkAltACL );
2331  if( cryptStatusError( status ) )
2332  return( status );
2333 
2334  /* If there's an alternative check ACL present, there's a requirement for
2335  a particular dependent object */
2336  if( checkAltACL != NULL )
2337  {
2338  if( !isValidObject( dependentObject ) || \
2339  checkAltACL->depObject != dependentType )
2340  return( CRYPT_ARGERROR_OBJECT );
2341  localMessageValue = checkAltACL->fdCheckType;
2342  }
2343  else
2344  {
2345  /* If there's no context : certificate relationship between the
2346  objects, don't do anything */
2347  if( !isValidObject( dependentObject ) || \
2348  ( !( objectType == OBJECT_TYPE_CONTEXT && \
2349  dependentType == OBJECT_TYPE_CERTIFICATE ) && \
2350  !( objectType == OBJECT_TYPE_CERTIFICATE && \
2351  dependentType == OBJECT_TYPE_CONTEXT ) ) )
2352  return( CRYPT_OK );
2353  }
2354 
2355  /* Postcondition */
2356  ENSURES( isValidObject( dependentObject ) );
2357  ENSURES( isSameOwningObject( objectHandle, dependentObject ) );
2358 
2359  /* Forward the message to the dependent object. We have to make the
2360  message internal since the dependent object may be internal-only.
2361  In addition we have to unlock the object table since the dependent
2362  object may currently be owned by another thread */
2363  MUTEX_UNLOCK( objectTable );
2364  status = krnlSendMessage( dependentObject, IMESSAGE_CHECK, NULL,
2365  localMessageValue );
2366  MUTEX_LOCK( objectTable );
2367  return( status );
2368  }
2369 
2370 /* Some objects can only perform given number of actions before they self-
2371  destruct, so if there's a usage count set we update it */
2372 
2373 CHECK_RETVAL \
2374 int postDispatchUpdateUsageCount( IN_HANDLE const int objectHandle,
2375  STDC_UNUSED const MESSAGE_TYPE dummy1,
2376  STDC_UNUSED const void *dummy2,
2377  STDC_UNUSED const int dummy3,
2378  STDC_UNUSED const void *dummy4 )
2379  {
2380  OBJECT_INFO *objectInfoPtr = &krnlData->objectTable[ objectHandle ];
2381  ORIGINAL_INT_VAR( usageCt, objectInfoPtr->usageCount );
2382 
2383  /* Precondition: It's a context with a nonzero usage count */
2384  REQUIRES( isValidObject( objectHandle ) && \
2385  objectInfoPtr->type == OBJECT_TYPE_CONTEXT );
2386  REQUIRES( objectInfoPtr->usageCount == CRYPT_UNUSED || \
2387  objectInfoPtr->usageCount > 0 );
2388 
2389  /* If there's an active usage count present, update it */
2390  if( objectInfoPtr->usageCount > 0 )
2391  objectInfoPtr->usageCount--;
2392 
2393  /* Postcondition: If there was a usage count it's been decremented and
2394  is >= 0 (the ground state) */
2395  ENSURES( objectInfoPtr->usageCount == CRYPT_UNUSED || \
2396  ( objectInfoPtr->usageCount == ORIGINAL_VALUE( usageCt ) - 1 && \
2397  objectInfoPtr->usageCount >= 0 ) );
2398  return( CRYPT_OK );
2399  }
2400 
2401 /* Certain messages can trigger changes in the object state from the low to
2402  the high state. Once one of these messages is successfully processed, we
2403  change the object's state so that further accesses are handled by the
2404  kernel based on the new state established by the message having been
2405  processed successfully. Since the object is still marked as busy at this
2406  stage, other messages arriving before the following state change can't
2407  bypass the kernel checks since they won't be processed until the object
2408  is marked as non-busy later on */
2409 
2410 CHECK_RETVAL \
2411 int postDispatchChangeState( IN_HANDLE const int objectHandle,
2412  STDC_UNUSED const MESSAGE_TYPE dummy1,
2413  STDC_UNUSED const void *dummy2,
2414  STDC_UNUSED const int dummy3,
2415  STDC_UNUSED const void *dummy4 )
2416  {
2417  /* Precondition: Object is in the low state so a state change message is
2418  valid */
2419  REQUIRES( isValidObject( objectHandle ) );
2420  REQUIRES( !isInHighState( objectHandle ) );
2421 
2422  /* The state change message was successfully processed, the object is now
2423  in the high state */
2424  krnlData->objectTable[ objectHandle ].flags |= OBJECT_FLAG_HIGH;
2425 
2426  /* Postcondition: Object is in the high state */
2427  ENSURES( isInHighState( objectHandle ) );
2428  return( CRYPT_OK );
2429  }
2430 
2431 CHECK_RETVAL \
2432 int postDispatchChangeStateOpt( IN_HANDLE const int objectHandle,
2433  STDC_UNUSED const MESSAGE_TYPE dummy1,
2434  STDC_UNUSED const void *dummy2,
2435  const int messageValue,
2436  IN TYPECAST( ATTRIBUTE_ACL * ) const void *auxInfo )
2437  {
2438  const ATTRIBUTE_ACL *attributeACL = ( ATTRIBUTE_ACL * ) auxInfo;
2439 
2440  assert( isReadPtr( attributeACL, sizeof( ATTRIBUTE_ACL ) ) );
2441 
2442  /* Precondition. If we're closing down then a background polling thread
2443  may still be trying to send entropy data to the system object, so we
2444  don't complain if this is the case */
2445  REQUIRES( ( krnlData->shutdownLevel >= SHUTDOWN_LEVEL_THREADS && \
2446  objectHandle == SYSTEM_OBJECT_HANDLE && \
2447  messageValue == CRYPT_IATTRIBUTE_ENTROPY ) || \
2448  isValidObject( objectHandle ) );
2449 
2450  /* If it's an attribute that triggers a state change, change the state */
2451  if( attributeACL->flags & ATTRIBUTE_FLAG_TRIGGER )
2452  {
2453  /* Inner precondition: Object is in the low state so a state change
2454  message is valid, or it's a retriggerable attribute that can be
2455  added multiple times (in other words, it can be added in both
2456  the low and high state, with the first add in the low state
2457  triggering a transition into the high state and subsequent
2458  additions augmenting the existing data) */
2459  REQUIRES( !isInHighState( objectHandle ) || \
2460  ( ( attributeACL->access & ACCESS_INT_xWx_xWx ) == \
2461  ACCESS_INT_xWx_xWx ) );
2462 
2463  krnlData->objectTable[ objectHandle ].flags |= OBJECT_FLAG_HIGH;
2464 
2465  /* Postcondition: Object is in the high state */
2466  ENSURES( isInHighState( objectHandle ) );
2467  return( CRYPT_OK );
2468  }
2469 
2470  /* Postcondition: It wasn't a trigger message */
2471  ENSURES( !( attributeACL->flags & ATTRIBUTE_FLAG_TRIGGER ) );
2472  return( CRYPT_OK );
2473  }
2474 
2475 /* It's a user management message, if it's a zeroise trigger a shutdown of
2476  the kernel */
2477 
2478 CHECK_RETVAL \
2479 int postDispatchHandleZeroise( IN_HANDLE const int objectHandle,
2480  IN_MESSAGE const MESSAGE_TYPE message,
2481  STDC_UNUSED const void *dummy2,
2482  IN_ENUM( MESSAGE_USERMGMT ) const int messageValue,
2483  STDC_UNUSED const void *dummy3 )
2484  {
2485  STDC_UNUSED \
2486  const OBJECT_INFO *objectTable = krnlData->objectTable;
2487  STDC_UNUSED \
2488  const MESSAGE_TYPE localMessage = message & MESSAGE_MASK;
2489 
2490  REQUIRES( fullObjectCheck( objectHandle, message ) && \
2491  objectTable[ objectHandle ].type == OBJECT_TYPE_USER );
2492  REQUIRES( localMessage == MESSAGE_USER_USERMGMT );
2493  REQUIRES( messageValue > MESSAGE_USERMGMT_NONE && \
2494  messageValue < MESSAGE_USERMGMT_LAST );
2495 
2496  /* If it's not a zeroise operation, we're done */
2497  if( messageValue != MESSAGE_USERMGMT_ZEROISE )
2498  return( CRYPT_OK );
2499 
2500  /* We're about to shut down, give any threads a chance to bail out */
2502 
2503  return( CRYPT_OK );
2504  }