cryptlib  3.4.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros
res_actn.c
Go to the documentation of this file.
1 /****************************************************************************
2 * *
3 * cryptlib Envelope Action Management *
4 * Copyright Peter Gutmann 1996-2008 *
5 * *
6 ****************************************************************************/
7 
8 #if defined( INC_ALL )
9  #include "envelope.h"
10 #else
11  #include "envelope/envelope.h"
12 #endif /* Compiler-specific includes */
13 
14 /* The maximum number of actions that we can add to an action list */
15 
16 #define MAX_ACTIONS FAILSAFE_ITERATIONS_MED - 1
17 
18 #ifdef USE_ENVELOPES
19 
20 /****************************************************************************
21 * *
22 * Find an Action *
23 * *
24 ****************************************************************************/
25 
26 /* Find an action of a given type and the last action of a given type.
27  Since the lists are sorted by action type, the generic findAction()
28  finds the start of an action group.
29 
30  The casting to a non-const is a bit ugly but is necessitated by the fact
31  that while the functions don't change the action list entries, the caller
32  will */
33 
34 CHECK_RETVAL_PTR \
35 ACTION_LIST *findAction( IN_OPT const ACTION_LIST *actionListPtr,
36  IN_ENUM( ACTION ) const ACTION_TYPE actionType )
37  {
38  int iterationCount;
39 
40  assert( actionListPtr == NULL || \
41  isReadPtr( actionListPtr, sizeof( ACTION_LIST ) ) );
42 
43  REQUIRES_N( actionType == ACTION_KEYEXCHANGE_PKC || \
44  actionType == ACTION_KEYEXCHANGE || \
45  actionType == ACTION_xxx || \
46  actionType == ACTION_CRYPT || \
47  actionType == ACTION_MAC || \
48  actionType == ACTION_HASH || \
49  actionType == ACTION_SIGN );
50 
51  for( iterationCount = 0;
52  actionListPtr != NULL && iterationCount < FAILSAFE_ITERATIONS_MED;
53  actionListPtr = actionListPtr->next, iterationCount++ )
54  {
55  if( actionListPtr->action == actionType )
56  return( ( ACTION_LIST * ) actionListPtr );
57  }
58  ENSURES_N( iterationCount < FAILSAFE_ITERATIONS_MED );
59 
60  return( NULL );
61  }
62 
64 ACTION_LIST *findLastAction( const ACTION_LIST *actionListPtr,
65  IN_ENUM( ACTION ) const ACTION_TYPE actionType )
66  {
67  int iterationCount;
68 
69  assert( actionListPtr == NULL || \
70  isReadPtr( actionListPtr, sizeof( ACTION_LIST ) ) );
71 
72  REQUIRES_N( actionType == ACTION_KEYEXCHANGE_PKC || \
73  actionType == ACTION_KEYEXCHANGE || \
74  actionType == ACTION_CRYPT || \
75  actionType == ACTION_MAC || \
76  actionType == ACTION_HASH || \
77  actionType == ACTION_SIGN );
78 
79  /* Find the start of the action group */
80  actionListPtr = findAction( actionListPtr, actionType );
81  if( actionListPtr == NULL )
82  return( NULL );
83 
84  /* Find the end of the action group */
85  for( iterationCount = 0;
86  actionListPtr->next != NULL && \
87  iterationCount < FAILSAFE_ITERATIONS_MED;
88  actionListPtr = actionListPtr->next, iterationCount++ )
89  {
90  if( actionListPtr->next->action != actionType )
91  break;
92  }
93  ENSURES_N( iterationCount < FAILSAFE_ITERATIONS_MED );
94 
95  return( ( ACTION_LIST * ) actionListPtr );
96  }
97 
98 /* An indirect action-check function that uses a caller-supplied callback to
99  verify a match for an action */
100 
102 ACTION_LIST *findActionIndirect( const ACTION_LIST *actionListStart,
103  IN CHECKACTIONFUNCTION checkActionFunction,
104  IN_INT_Z const int intParam )
105  {
106  const ACTION_LIST *actionListPtr;
107  int iterationCount;
108 
109  assert( isReadPtr( actionListStart, sizeof( ACTION_LIST ) ) );
110 
111  REQUIRES_N( checkActionFunction != NULL );
112 
113  for( actionListPtr = actionListStart, iterationCount = 0;
114  actionListPtr != NULL && iterationCount < FAILSAFE_ITERATIONS_MED;
115  actionListPtr = actionListPtr->next, iterationCount++ )
116  {
117  const int status = checkActionFunction( actionListPtr, intParam );
118  if( cryptStatusOK( status ) )
119  return( ( ACTION_LIST * ) actionListPtr );
120  }
121  ENSURES_N( iterationCount < FAILSAFE_ITERATIONS_MED );
122 
123  return( NULL );
124  }
125 
126 /****************************************************************************
127 * *
128 * Add/Delete an Action *
129 * *
130 ****************************************************************************/
131 
132 /* Check whether more actions can be added to an action list */
133 
134 CHECK_RETVAL_BOOL \
135 BOOLEAN moreActionsPossible( IN_OPT const ACTION_LIST *actionListPtr )
136  {
137  int actionCount;
138 
139  assert( actionListPtr == NULL || \
140  isReadPtr( actionListPtr, sizeof( ACTION_LIST ) ) );
141 
142  for( actionCount = 0;
143  actionListPtr != NULL && actionCount < FAILSAFE_ITERATIONS_MED;
144  actionListPtr = actionListPtr->next, actionCount++ );
145  ENSURES_B( actionCount < FAILSAFE_ITERATIONS_MED );
146 
147  return( ( actionCount < MAX_ACTIONS ) ? TRUE : FALSE );
148  }
149 
150 /* Add a new action to the end of an action group in an action list */
151 
152 CHECK_RETVAL STDC_NONNULL_ARG( ( 2, 3 ) ) \
153 static int createNewAction( OUT_OPT_PTR_OPT ACTION_LIST **newActionPtrPtr,
156  IN_ENUM( ACTION ) const ACTION_TYPE actionType,
158  {
159  ACTION_LIST *actionListPtr, *prevActionPtr = NULL;
160  ACTION_LIST *newItem;
161  int iterationCount;
162 
163  assert( newActionPtrPtr == NULL || \
164  isWritePtr( newActionPtrPtr, sizeof( ACTION_LIST * ) ) );
165  assert( isWritePtr( actionListHeadPtrPtr, sizeof( ACTION_LIST * ) ) );
166  assert( isWritePtr( memPoolState, sizeof( MEMPOOL_STATE ) ) );
167 
168  REQUIRES( actionType == ACTION_KEYEXCHANGE_PKC || \
169  actionType == ACTION_KEYEXCHANGE || \
170  actionType == ACTION_xxx || \
171  actionType == ACTION_CRYPT || \
172  actionType == ACTION_MAC || \
173  actionType == ACTION_HASH || \
174  actionType == ACTION_SIGN );
175  REQUIRES( isHandleRangeValid( cryptHandle ) );
176 
177  /* Clear return value */
178  if( newActionPtrPtr != NULL )
179  *newActionPtrPtr = NULL;
180 
181  /* Create the new action list item */
182  if( ( newItem = getMemPool( memPoolState, \
183  sizeof( ACTION_LIST ) ) ) == NULL )
184  return( CRYPT_ERROR_MEMORY );
185  memset( newItem, 0, sizeof( ACTION_LIST ) );
186  newItem->action = actionType;
187  newItem->iCryptHandle = cryptHandle;
188  newItem->iExtraData = CRYPT_ERROR;
189  newItem->iTspSession = CRYPT_ERROR;
190 
191  /* Find the last action in the action group */
192  for( actionListPtr = *actionListHeadPtrPtr, iterationCount = 0;
193  actionListPtr != NULL && actionListPtr->action <= actionType && \
194  iterationCount < FAILSAFE_ITERATIONS_MED;
195  actionListPtr = actionListPtr->next, iterationCount++ )
196  {
197  prevActionPtr = actionListPtr;
198  }
199  ENSURES( iterationCount < FAILSAFE_ITERATIONS_MED );
200 
201  /* Append the new action */
202  insertSingleListElement( actionListHeadPtrPtr, prevActionPtr, newItem );
203  if( newActionPtrPtr != NULL )
204  *newActionPtrPtr = newItem;
205 
206  return( CRYPT_OK );
207  }
208 
209 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 3 ) ) \
210 int addActionEx( OUT_OPT_PTR_OPT ACTION_LIST **newActionPtrPtr,
211  OUT_PTR ACTION_LIST **actionListHeadPtrPtr,
212  INOUT MEMPOOL_STATE memPoolState,
213  IN_ENUM( ACTION ) const ACTION_TYPE actionType,
214  IN_HANDLE const CRYPT_HANDLE cryptHandle )
215  {
216  assert( isWritePtr( newActionPtrPtr, sizeof( ACTION_LIST * ) ) );
217  /* Rest are checked in createNewAction() */
218 
219  return( createNewAction( newActionPtrPtr, actionListHeadPtrPtr,
220  memPoolState, actionType, cryptHandle ) );
221  }
222 
223 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
224 int addAction( OUT_PTR ACTION_LIST **actionListHeadPtrPtr,
225  INOUT MEMPOOL_STATE memPoolState,
226  IN_ENUM( ACTION ) const ACTION_TYPE actionType,
227  IN_HANDLE const CRYPT_HANDLE cryptHandle )
228  {
229  return( createNewAction( NULL, actionListHeadPtrPtr, memPoolState,
230  actionType, cryptHandle ) );
231  }
232 
233 /* Delete an action from an action list */
234 
235 STDC_NONNULL_ARG( ( 1, 2 ) ) \
236 static void deleteActionListItem( INOUT MEMPOOL_STATE memPoolState,
237  INOUT ACTION_LIST *actionListItem )
238  {
239  assert( isWritePtr( memPoolState, sizeof( MEMPOOL_STATE ) ) );
240  assert( isWritePtr( actionListItem, sizeof( ACTION_LIST ) ) );
241 
242  /* Destroy any attached objects and information if necessary and
243  clear the list item memory */
244  if( actionListItem->iCryptHandle != CRYPT_ERROR )
245  krnlSendNotifier( actionListItem->iCryptHandle, IMESSAGE_DECREFCOUNT );
246  if( actionListItem->iExtraData != CRYPT_ERROR )
247  krnlSendNotifier( actionListItem->iExtraData, IMESSAGE_DECREFCOUNT );
248  if( actionListItem->iTspSession != CRYPT_ERROR )
249  krnlSendNotifier( actionListItem->iTspSession, IMESSAGE_DECREFCOUNT );
250  zeroise( actionListItem, sizeof( ACTION_LIST ) );
251  freeMemPool( memPoolState, actionListItem );
252  }
253 
254 STDC_NONNULL_ARG( ( 1, 2, 3 ) ) \
255 static int deleteAction( INOUT_PTR ACTION_LIST **actionListHeadPtrPtr,
256  INOUT MEMPOOL_STATE memPoolState,
257  INOUT ACTION_LIST *actionListItem )
258  {
259  ACTION_LIST *listPrevPtr;
260  int iterationCount;
261 
262  assert( isWritePtr( actionListHeadPtrPtr, sizeof( ACTION_LIST * ) ) );
263  assert( isWritePtr( memPoolState, sizeof( MEMPOOL_STATE ) ) );
264  assert( isWritePtr( actionListItem, sizeof( ACTION_LIST ) ) );
265 
266  REQUIRES( *actionListHeadPtrPtr != NULL );
267 
268  /* Find the previons entry in the list */
269  for( listPrevPtr = *actionListHeadPtrPtr, iterationCount = 0;
270  listPrevPtr != NULL && listPrevPtr->next != actionListItem && \
271  iterationCount < FAILSAFE_ITERATIONS_MED;
272  listPrevPtr = listPrevPtr->next, iterationCount++ );
273  ENSURES( iterationCount < FAILSAFE_ITERATIONS_MED );
274 
275  /* Remove the item from the list */
276  deleteSingleListElement( actionListHeadPtrPtr, listPrevPtr,
277  actionListItem );
278 
279  /* Clear all data in the list item and free the memory */
280  deleteActionListItem( memPoolState, actionListItem );
281 
282  return( CRYPT_OK );
283  }
284 
285 /* Delete an action list */
286 
287 STDC_NONNULL_ARG( ( 1, 2 ) ) \
288 void deleteActionList( INOUT MEMPOOL_STATE memPoolState,
289  INOUT ACTION_LIST *actionListPtr )
290  {
291  int iterationCount;
292 
293  assert( isWritePtr( memPoolState, sizeof( MEMPOOL_STATE ) ) );
294  assert( isReadPtr( actionListPtr, sizeof( ACTION_LIST ) ) );
295 
296  for( iterationCount = 0;
297  actionListPtr != NULL && \
298  iterationCount < FAILSAFE_ITERATIONS_MED;
299  iterationCount++ )
300  {
301  ACTION_LIST *actionListItem = actionListPtr;
302 
303  actionListPtr = actionListPtr->next;
304  deleteActionListItem( memPoolState, actionListItem );
305  }
306  ENSURES_V( iterationCount < FAILSAFE_ITERATIONS_MED );
307  }
308 
309 /* Delete any orphaned actions, for example automatically-added hash actions
310  that were overridden by user-supplied alternate actions */
311 
312 STDC_NONNULL_ARG( ( 1 ) ) \
313 int deleteUnusedActions( INOUT ENVELOPE_INFO *envelopeInfoPtr )
314  {
316  int iterationCount, status;
317 
318  assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
319 
320  /* Check for unattached encryption, hash/MAC, or generic-secret actions
321  and delete them */
322  for( actionListPtr = envelopeInfoPtr->actionList, iterationCount = 0;
323  actionListPtr != NULL && \
324  iterationCount < FAILSAFE_ITERATIONS_MED;
325  iterationCount++ )
326  {
327  ACTION_LIST *actionListCurrent = actionListPtr;
328 
329  actionListPtr = actionListPtr->next;
330  if( ( actionListCurrent->action == ACTION_CRYPT || \
331  actionListCurrent->action == ACTION_HASH || \
332  actionListCurrent->action == ACTION_MAC || \
333  actionListCurrent->action == ACTION_xxx ) && \
334  ( actionListCurrent->flags & ACTION_NEEDSCONTROLLER ) )
335  {
336  status = deleteAction( &envelopeInfoPtr->actionList,
337  envelopeInfoPtr->memPoolState,
338  actionListCurrent );
339  if( cryptStatusError( status ) )
340  return( status );
341  }
342  }
343  ENSURES( iterationCount < FAILSAFE_ITERATIONS_MED );
344 
345  return( CRYPT_OK );
346  }
347 
348 /****************************************************************************
349 * *
350 * Check an Action *
351 * *
352 ****************************************************************************/
353 
354 /* Check a new action to make sure that it isn't already present in the
355  action list, producing an ACTION_RESULT outcome */
356 
357 CHECK_RETVAL_ENUM( ACTION ) \
358 ACTION_RESULT checkAction( IN_OPT const ACTION_LIST *actionListStart,
359  IN_ENUM( ACTION ) const ACTION_TYPE actionType,
360  IN_HANDLE const CRYPT_HANDLE cryptHandle )
361  {
362  ACTION_LIST *actionListPtr = ( ACTION_LIST * ) actionListStart;
364  BYTE keyID[ KEYID_SIZE + 8 ];
365  int algorithm = DUMMY_INIT, iterationCount, status;
366 
367  assert( actionListPtr == NULL || \
368  isReadPtr( actionListPtr, sizeof( ACTION_LIST ) ) );
369 
370  REQUIRES_EXT( ( actionType == ACTION_KEYEXCHANGE_PKC || \
371  actionType == ACTION_KEYEXCHANGE || \
372  actionType == ACTION_CRYPT || \
373  actionType == ACTION_MAC || \
374  actionType == ACTION_HASH || \
375  actionType == ACTION_SIGN ), ACTION_RESULT_ERROR );
377 
378  /* If the action list is empty, there's nothing to check */
379  if( actionListPtr == NULL )
380  return( ACTION_RESULT_EMPTY );
381 
382  /* Get identification information for the action object */
383  switch( actionType )
384  {
385  case ACTION_KEYEXCHANGE:
386  /* For conventional key wrap we can't really do much, for raw
387  action objects we'd check the algorithm for duplicates but
388  it's perfectly valid to wrap a single session/MAC key using
389  multiple key wrap objects with the same algorithm */
390  status = CRYPT_OK;
391  break;
392 
394  case ACTION_SIGN:
395  /* It's a PKC object, get the key ID */
396  setMessageData( &msgData, keyID, KEYID_SIZE );
397  status = krnlSendMessage( cryptHandle, IMESSAGE_GETATTRIBUTE_S,
398  &msgData, CRYPT_IATTRIBUTE_KEYID );
399  break;
400 
401  case ACTION_HASH:
402  case ACTION_MAC:
403  case ACTION_CRYPT:
404  /* It's a raw action object, get the algorithm */
405  status = krnlSendMessage( cryptHandle, IMESSAGE_GETATTRIBUTE,
406  &algorithm, CRYPT_CTXINFO_ALGO );
407  break;
408 
409  default:
411  }
412  if( cryptStatusError( status ) )
413  return( ACTION_RESULT_ERROR );
414 
415  /* Walk down the list from the first to the last action in the action
416  group checking each one in turn */
417  for( actionListPtr = findAction( actionListPtr, actionType ), \
418  iterationCount = 0;
419  actionListPtr != NULL && actionListPtr->action == actionType && \
420  iterationCount < FAILSAFE_ITERATIONS_MED;
421  actionListPtr = actionListPtr->next, iterationCount++ )
422  {
423  BOOLEAN isDuplicate = FALSE;
424  int actionAlgo;
425 
426  /* Make sure that we haven't added this action already. This can
427  get a bit tricky both because detecting some types of duplicates
428  is rather hard and because the definition of what's an invalid
429  duplicate varies somewhat. For a hash, MAC, and encryption
430  action we only allow one action of a given algorithm type to
431  be added. For a PKC key exchange or signature action we only
432  allow one action for a given key to be added. For a conventional
433  key exchange action we should in theory check for duplicates in
434  some form but it's not certain what constitutes a duplicate (for
435  example are two otherwise identical actions with a different
436  number of key setup iterations considered duplicates or not?) so
437  for now we assume that the user won't do anything silly (in any
438  case for any key exchange action the only thing that a duplicate
439  will do is result in unnecessary bloating of the envelope
440  header).
441 
442  In addition to the more sophisticated checks we also perform a
443  few more basic ones for the same object being added twice, which
444  doesn't catch e.g. inadvertent use of the same keying material
445  but does catch simple programming errors */
446  if( actionListPtr->iCryptHandle == cryptHandle )
447  return( ACTION_RESULT_INITED );
448  switch( actionType )
449  {
450  case ACTION_KEYEXCHANGE:
451  /* It's a conventional key exchange, there's not much that
452  we can check */
453  break;
454 
456  case ACTION_SIGN:
457  /* It's a PKC key exchange or signature action, compare the
458  two objects by comparing their keys */
459  setMessageData( &msgData, keyID, KEYID_SIZE );
460  if( cryptStatusOK( \
461  krnlSendMessage( actionListPtr->iCryptHandle,
462  IMESSAGE_COMPARE, &msgData,
464  isDuplicate = TRUE;
465  break;
466 
467  case ACTION_HASH:
468  case ACTION_MAC:
469  case ACTION_CRYPT:
470  /* It's a hash/MAC or session key object, compare the two
471  objects by comparing their algorithms */
472  if( cryptStatusOK( \
473  krnlSendMessage( actionListPtr->iCryptHandle,
474  IMESSAGE_GETATTRIBUTE, &actionAlgo,
475  CRYPT_CTXINFO_ALGO ) ) && \
476  actionAlgo == algorithm )
477  isDuplicate = TRUE;
478  break;
479 
480  }
481  if( isDuplicate )
482  {
483  /* If the action was added automatically/implicitly as the
484  result of adding another action then the first attempt to add
485  it explicitly by the caller isn't an error. The caller will
486  treat the ACTION_RESULT_PRESENT code as CRYPT_OK */
487  if( actionListPtr->flags & ACTION_ADDEDAUTOMATICALLY )
488  {
489  actionListPtr->flags &= ~ACTION_ADDEDAUTOMATICALLY;
490  return( ACTION_RESULT_PRESENT );
491  }
492 
493  return( ACTION_RESULT_INITED );
494  }
495  }
496  ENSURES_EXT( ( iterationCount < FAILSAFE_ITERATIONS_MED ), \
498 
499  return( ACTION_RESULT_OK );
500  }
501 
502 /* An indirect action-check function that uses a caller-supplied callback to
503  verify each action */
504 
505 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
506 int checkActionIndirect( const ACTION_LIST *actionListStart,
507  IN CHECKACTIONFUNCTION checkActionFunction,
508  IN_INT_Z const int intParam )
509  {
510  const ACTION_LIST *actionListPtr;
511  int iterationCount;
512 
513  assert( isReadPtr( actionListStart, sizeof( ACTION_LIST ) ) );
514 
515  REQUIRES( checkActionFunction != NULL );
516 
517  for( actionListPtr = actionListStart, iterationCount = 0;
518  actionListPtr != NULL && iterationCount < FAILSAFE_ITERATIONS_MED;
519  actionListPtr = actionListPtr->next, iterationCount++ )
520  {
521  const int status = checkActionFunction( actionListPtr, intParam );
522  if( cryptStatusError( status ) )
523  return( status );
524  }
525  ENSURES( iterationCount < FAILSAFE_ITERATIONS_MED );
526 
527  return( CRYPT_OK );
528  }
529 
530 /* Perform a sanity-check to ensure that the actions in an envelope are
531  consistent. There are two approaches to this, take the envelope usage
532  and check that everything is consistent with it, or take the actions
533  and make sure that they're consistent with the usage (and each other).
534  We perform the latter type of check, which is somewhat simpler. The
535  requirements that we enforce are:
536 
537  | Pre | In | Post |
538  --------+-----------+-----------+-----------+-----
539  SIG | - | Hash | Sig | CMS
540  | - | 1x Hash | 1x Sig | PGP
541  --------+-----------+-----------+-----------+-----
542  MAC | Keyex,PKC | 1x MAC | - | CMS
543  | - | - | - | PGP
544  --------+-----------+-----------+-----------+-----
545  COPR | - | - | - | CMS
546  | - | - | - | PGP
547  --------+-----------+-----------+-----------+-----
548  ENCR | Keyex,PKC | Crypt | - | CMS
549  | PKC | 1x Crypt | - | PGP
550 
551  In the case of ENCR the pre-actions can be absent if we're using raw
552  session-key encryption */
553 
555 BOOLEAN checkActions( INOUT ENVELOPE_INFO *envelopeInfoPtr )
556  {
558  int iterationCount;
559 
560  assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
561 
562  /* If there are no pre-, post-, or main actions (i.e. it's a compressed
563  or data-only envelope), we're done */
564  if( envelopeInfoPtr->actionList == NULL )
565  {
566  /* Make sure that the envelope has the appropriate usage for these
567  actions */
568  if( envelopeInfoPtr->usage != ACTION_COMPRESS && \
569  envelopeInfoPtr->usage != ACTION_NONE )
570  return( FALSE );
571 
572  /* There can be no pre- or post-actions present for this usage */
573  if( envelopeInfoPtr->preActionList != NULL || \
574  envelopeInfoPtr->postActionList != NULL )
575  return( FALSE );
576 
577  return( TRUE );
578  }
579 
580  /* If there are pre-actions it has to be a key exchange followed by
581  encryption or MAC actions */
582  if( envelopeInfoPtr->preActionList != NULL )
583  {
584  int cryptActionCount = 0, macActionCount = 0;
585  int genericSecretActionCount = 0;
586 
587  /* Make sure that the envelope has the appropriate usage for these
588  actions */
589  if( envelopeInfoPtr->usage != ACTION_CRYPT && \
590  envelopeInfoPtr->usage != ACTION_MAC )
591  return( FALSE );
592 
593  /* Pre-actions can only be key exchange actions and have to be sorted
594  by action group */
595  for( actionListPtr = envelopeInfoPtr->preActionList, \
596  iterationCount = 0;
597  actionListPtr != NULL && \
598  actionListPtr->action == ACTION_KEYEXCHANGE_PKC && \
599  iterationCount < FAILSAFE_ITERATIONS_MED;
600  actionListPtr = actionListPtr->next, iterationCount++ );
601  ENSURES_B( iterationCount < FAILSAFE_ITERATIONS_MED );
602  if( envelopeInfoPtr->type == CRYPT_FORMAT_PGP && \
603  actionListPtr != NULL )
604  {
605  /* PGP can't have any conventional keyex actions since the
606  password is used to directly derive the session key */
607  return( FALSE );
608  }
609  for( iterationCount = 0;
610  actionListPtr != NULL && \
611  actionListPtr->action == ACTION_KEYEXCHANGE && \
612  iterationCount < FAILSAFE_ITERATIONS_MED;
613  actionListPtr = actionListPtr->next, iterationCount++ );
614  ENSURES_B( iterationCount < FAILSAFE_ITERATIONS_MED );
615  if( actionListPtr != NULL )
616  return( FALSE );
617  ENSURES_B( envelopeInfoPtr->actionList != NULL );
618 
619  /* Key exchange must be followed by a single crypt, one or more
620  MAC actions, or a sequence of { generic-secret, crypt, MAC }
621  actions. First we count the actions present */
622  for( actionListPtr = envelopeInfoPtr->actionList, iterationCount = 0;
623  actionListPtr != NULL && \
624  iterationCount < FAILSAFE_ITERATIONS_MED;
625  actionListPtr = actionListPtr->next, iterationCount++ )
626  {
627  switch( actionListPtr->action )
628  {
629  case ACTION_xxx:
630  genericSecretActionCount++;
631  break;
632 
633  case ACTION_CRYPT:
634  cryptActionCount++;
635  break;
636 
637  case ACTION_MAC:
638  macActionCount++;
639  break;
640 
641  default:
642  return( FALSE );
643  }
644  }
645  ENSURES_B( iterationCount < FAILSAFE_ITERATIONS_MED );
646 
647  /* Then we make sure that what's present follows the requirements
648  given above */
649  if( genericSecretActionCount > 0 )
650  {
651  /* AuthEnc envelope, we need a sequence of { generic-secret,
652  crypt, MAC } */
653  if( genericSecretActionCount != 1 || \
654  cryptActionCount != 1 || macActionCount != 1 )
655  return( FALSE );
656  }
657  else
658  {
659  if( cryptActionCount > 0 )
660  {
661  /* Encrypted envelope, we need a single encryption action */
662  if( cryptActionCount > 1 || \
663  genericSecretActionCount != 0 || macActionCount != 0 )
664  return( FALSE );
665  }
666  else
667  {
668  /* MACed envelope, we need one or more MAC actions */
669  if( genericSecretActionCount != 0 || cryptActionCount != 0 )
670  return( FALSE );
671  }
672  }
673 
674  /* PGP doesn't support MACed envelopes or AuthEnc encryption */
675  if( envelopeInfoPtr->type == CRYPT_FORMAT_PGP && \
676  ( macActionCount != 0 || genericSecretActionCount != 0 ) )
677  return( FALSE );
678 
679  /* There can't be any post-actions */
680  if( envelopeInfoPtr->postActionList != NULL )
681  return( FALSE );
682 
683  return( TRUE );
684  }
685 
686  /* If there are post-actions it has to be a hash follwed by signature
687  actions */
688  if( envelopeInfoPtr->postActionList != NULL )
689  {
690  int hashActionCount = 0, sigActionCount = 0;
691 
692  /* Make sure that the envelope has the appropriate usage for these
693  actions */
694  if( envelopeInfoPtr->usage != ACTION_SIGN )
695  return( FALSE );
696 
697  /* There can't be any pre-actions */
698  if( envelopeInfoPtr->preActionList != NULL )
699  return( FALSE );
700 
701  /* The signature must be preceded by one or more hash actions */
702  if( envelopeInfoPtr->actionList == NULL )
703  return( FALSE );
704  for( actionListPtr = envelopeInfoPtr->actionList, iterationCount = 0;
705  actionListPtr != NULL && \
706  iterationCount < FAILSAFE_ITERATIONS_MED;
707  actionListPtr = actionListPtr->next, iterationCount++ )
708  {
709  if( actionListPtr->action != ACTION_HASH )
710  return( FALSE );
711  hashActionCount++;
712  }
713  ENSURES_B( iterationCount < FAILSAFE_ITERATIONS_MED );
714 
715  /* PGP can only have a single hash per signed envelope */
716  if( envelopeInfoPtr->type == CRYPT_FORMAT_PGP && hashActionCount > 1 )
717  return( FALSE );
718 
719  /* Hash actions must be followed by one or more signature actions */
720  for( actionListPtr = envelopeInfoPtr->postActionList, \
721  iterationCount = 0;
722  actionListPtr != NULL && \
723  iterationCount < FAILSAFE_ITERATIONS_MED;
724  actionListPtr = actionListPtr->next, iterationCount++ )
725  {
726  if( actionListPtr->action != ACTION_SIGN )
727  return( FALSE );
728  sigActionCount++;
729  }
730  ENSURES_B( iterationCount < FAILSAFE_ITERATIONS_MED );
731 
732  /* PGP can only have a single signature, multiple signatures are
733  handled by nesting envelopes */
734  if( envelopeInfoPtr->type == CRYPT_FORMAT_PGP && sigActionCount > 1 )
735  return( FALSE );
736 
737  return( TRUE );
738  }
739 
740  /* If there's a standalone session-key encryption action, it has to be
741  the only action present */
742  actionListPtr = envelopeInfoPtr->actionList;
743  ENSURES_B( actionListPtr != NULL );
744  if( actionListPtr->action == ACTION_CRYPT )
745  {
746  /* Make sure that the envelope has the appropriate usage for these
747  actions */
748  if( envelopeInfoPtr->usage != ACTION_CRYPT )
749  return( FALSE );
750 
751  /* If we're performing authenticated encryption then the encryption
752  action has to be followed by a MAC action */
753  if( envelopeInfoPtr->flags & ENVELOPE_AUTHENC )
754  {
755  actionListPtr = actionListPtr->next;
756  if( actionListPtr == NULL || \
757  actionListPtr->action != ACTION_MAC || \
758  actionListPtr->next != NULL )
759  return( FALSE );
760 
761  return( TRUE );
762  }
763 
764  /* PGP can optionally follow an encryption action with a hash action
765  for encryption with MDC */
766  if( envelopeInfoPtr->type == CRYPT_FORMAT_PGP && \
767  actionListPtr->next != NULL )
768  {
769  actionListPtr = actionListPtr->next;
770  if( actionListPtr->action != ACTION_HASH || \
771  actionListPtr->next != NULL )
772  return( FALSE );
773 
774  return( TRUE );
775  }
776 
777  /* There can only be one encryption action present */
778  if( actionListPtr->next != NULL )
779  return( FALSE );
780 
781  return( TRUE );
782  }
783 
784  /* If we're processing PGP-encrypted data with an MDC at the end of the
785  encrypted data then it's possible to have an encryption envelope with
786  a hash action (which must be followed by an encryption action) */
787  if( envelopeInfoPtr->type == CRYPT_FORMAT_PGP && \
788  actionListPtr->action == ACTION_HASH && \
789  actionListPtr->next != NULL && \
790  actionListPtr->next->action == ACTION_CRYPT )
791  {
792  ACTION_LIST *nextActionPtr = actionListPtr->next;
793 
794  /* Make sure that the envelope has the appropriate usage for these
795  actions */
796  if( envelopeInfoPtr->usage != ACTION_CRYPT )
797  return( FALSE );
798 
799  /* Make sure that the encryption action is the only other action */
800  if( nextActionPtr->action != ACTION_CRYPT || \
801  nextActionPtr->next != NULL )
802  return( FALSE );
803 
804  return( TRUE );
805  }
806 
807  /* If it's a MACd envelope there can only be a single MAC action
808  present */
809  if( envelopeInfoPtr->usage == ACTION_MAC )
810  {
811  /* Make sure that there's only a single MAC action present */
812  if( actionListPtr->action != ACTION_MAC || \
813  actionListPtr->next != NULL )
814  return( FALSE );
815 
816  return( TRUE );
817  }
818 
819  /* Anything else has to be a signing envelope */
820  if( envelopeInfoPtr->usage != ACTION_SIGN )
821  return( FALSE );
822 
823  /* When we're de-enveloping a signed envelope we can have standalone
824  hash actions before we get to the signature data and add post-
825  actions */
826  if( ( envelopeInfoPtr->flags & ENVELOPE_ISDEENVELOPE ) && \
827  actionListPtr->action == ACTION_HASH )
828  {
829  for( iterationCount = 0; \
830  actionListPtr != NULL && \
831  iterationCount < FAILSAFE_ITERATIONS_MED;
832  actionListPtr = actionListPtr->next, iterationCount++ )
833  {
834  if( actionListPtr->action != ACTION_HASH )
835  return( FALSE );
836  }
837  ENSURES_B( iterationCount < FAILSAFE_ITERATIONS_MED );
838 
839  return( TRUE );
840  }
841 
842  /* Everything else is an error */
843  return( FALSE );
844  }
845 #endif /* USE_ENVELOPES */