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 \
findAction(IN_OPT const ACTION_LIST * actionListPtr,IN_ENUM (ACTION)const ACTION_TYPE actionType)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
63 CHECK_RETVAL_PTR STDC_NONNULL_ARG( ( 1 ) ) \
findLastAction(const ACTION_LIST * actionListPtr,IN_ENUM (ACTION)const ACTION_TYPE actionType)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
101 CHECK_RETVAL_PTR STDC_NONNULL_ARG( ( 1, 2 ) ) \
findActionIndirect(const ACTION_LIST * actionListStart,IN CHECKACTION_FUNCTION checkActionFunction,IN_INT_Z const int intParam)102 ACTION_LIST *findActionIndirect( const ACTION_LIST *actionListStart,
103 IN CHECKACTION_FUNCTION 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 \
moreActionsPossible(IN_OPT const ACTION_LIST * actionListPtr)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 ) ) \
createNewAction(OUT_OPT_PTR_COND ACTION_LIST ** newActionPtrPtr,INOUT_PTR ACTION_LIST ** actionListHeadPtrPtr,INOUT MEMPOOL_STATE memPoolState,IN_ENUM (ACTION)const ACTION_TYPE actionType,IN_HANDLE const CRYPT_HANDLE cryptHandle)153 static int createNewAction( OUT_OPT_PTR_COND ACTION_LIST **newActionPtrPtr,
154 INOUT_PTR ACTION_LIST **actionListHeadPtrPtr,
155 INOUT MEMPOOL_STATE memPoolState,
156 IN_ENUM( ACTION ) const ACTION_TYPE actionType,
157 IN_HANDLE const CRYPT_HANDLE cryptHandle )
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 ) ) \
addActionEx(OUT_OPT_PTR_COND ACTION_LIST ** newActionPtrPtr,INOUT_PTR ACTION_LIST ** actionListHeadPtrPtr,INOUT MEMPOOL_STATE memPoolState,IN_ENUM (ACTION)const ACTION_TYPE actionType,IN_HANDLE const CRYPT_HANDLE cryptHandle)210 int addActionEx( OUT_OPT_PTR_COND ACTION_LIST **newActionPtrPtr,
211 INOUT_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 ) ) \
addAction(INOUT_PTR ACTION_LIST ** actionListHeadPtrPtr,INOUT MEMPOOL_STATE memPoolState,IN_ENUM (ACTION)const ACTION_TYPE actionType,IN_HANDLE const CRYPT_HANDLE cryptHandle)224 int addAction( INOUT_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 /* Replace a context in an action with a different one, used to update an
234 existing action when circumstances change */
235
236 STDC_NONNULL_ARG( ( 1 ) ) \
replaceAction(INOUT ACTION_LIST * actionListItem,IN_HANDLE const CRYPT_HANDLE cryptHandle)237 int replaceAction( INOUT ACTION_LIST *actionListItem,
238 IN_HANDLE const CRYPT_HANDLE cryptHandle )
239 {
240 assert( isWritePtr( actionListItem, sizeof( ACTION_LIST ) ) );
241
242 REQUIRES( isHandleRangeValid( cryptHandle ) );
243 REQUIRES( actionListItem->iCryptHandle != CRYPT_ERROR && \
244 actionListItem->iExtraData == CRYPT_ERROR && \
245 actionListItem->iTspSession == CRYPT_ERROR );
246
247 /* Delete the existing action context and replace it with the new one */
248 krnlSendNotifier( actionListItem->iCryptHandle, IMESSAGE_DECREFCOUNT );
249 actionListItem->iCryptHandle = cryptHandle;
250
251 return( CRYPT_OK );
252 }
253
254 /* Delete an action from an action list */
255
256 STDC_NONNULL_ARG( ( 1, 2 ) ) \
deleteActionListItem(INOUT MEMPOOL_STATE memPoolState,INOUT ACTION_LIST * actionListItem)257 static void deleteActionListItem( INOUT MEMPOOL_STATE memPoolState,
258 INOUT ACTION_LIST *actionListItem )
259 {
260 assert( isWritePtr( memPoolState, sizeof( MEMPOOL_STATE ) ) );
261 assert( isWritePtr( actionListItem, sizeof( ACTION_LIST ) ) );
262
263 /* Destroy any attached objects and information if necessary and
264 clear the list item memory */
265 if( actionListItem->iCryptHandle != CRYPT_ERROR )
266 krnlSendNotifier( actionListItem->iCryptHandle, IMESSAGE_DECREFCOUNT );
267 if( actionListItem->iExtraData != CRYPT_ERROR )
268 krnlSendNotifier( actionListItem->iExtraData, IMESSAGE_DECREFCOUNT );
269 if( actionListItem->iTspSession != CRYPT_ERROR )
270 krnlSendNotifier( actionListItem->iTspSession, IMESSAGE_DECREFCOUNT );
271 zeroise( actionListItem, sizeof( ACTION_LIST ) );
272 freeMemPool( memPoolState, actionListItem );
273 }
274
275 STDC_NONNULL_ARG( ( 1, 2, 3 ) ) \
deleteAction(INOUT_PTR ACTION_LIST ** actionListHeadPtrPtr,INOUT MEMPOOL_STATE memPoolState,INOUT ACTION_LIST * actionListItem)276 static int deleteAction( INOUT_PTR ACTION_LIST **actionListHeadPtrPtr,
277 INOUT MEMPOOL_STATE memPoolState,
278 INOUT ACTION_LIST *actionListItem )
279 {
280 ACTION_LIST *listPrevPtr;
281 int iterationCount;
282
283 assert( isWritePtr( actionListHeadPtrPtr, sizeof( ACTION_LIST * ) ) );
284 assert( isWritePtr( memPoolState, sizeof( MEMPOOL_STATE ) ) );
285 assert( isWritePtr( actionListItem, sizeof( ACTION_LIST ) ) );
286
287 REQUIRES( *actionListHeadPtrPtr != NULL );
288
289 /* Find the previons entry in the list */
290 for( listPrevPtr = *actionListHeadPtrPtr, iterationCount = 0;
291 listPrevPtr != NULL && listPrevPtr->next != actionListItem && \
292 iterationCount < FAILSAFE_ITERATIONS_MED;
293 listPrevPtr = listPrevPtr->next, iterationCount++ );
294 ENSURES( iterationCount < FAILSAFE_ITERATIONS_MED );
295
296 /* Remove the item from the list */
297 deleteSingleListElement( actionListHeadPtrPtr, listPrevPtr,
298 actionListItem );
299
300 /* Clear all data in the list item and free the memory */
301 deleteActionListItem( memPoolState, actionListItem );
302
303 return( CRYPT_OK );
304 }
305
306 /* Delete an action list */
307
308 STDC_NONNULL_ARG( ( 1, 2 ) ) \
deleteActionList(INOUT MEMPOOL_STATE memPoolState,INOUT ACTION_LIST * actionListPtr)309 void deleteActionList( INOUT MEMPOOL_STATE memPoolState,
310 INOUT ACTION_LIST *actionListPtr )
311 {
312 int iterationCount;
313
314 assert( isWritePtr( memPoolState, sizeof( MEMPOOL_STATE ) ) );
315 assert( isReadPtr( actionListPtr, sizeof( ACTION_LIST ) ) );
316
317 for( iterationCount = 0;
318 actionListPtr != NULL && \
319 iterationCount < FAILSAFE_ITERATIONS_MED;
320 iterationCount++ )
321 {
322 ACTION_LIST *actionListItem = actionListPtr;
323
324 actionListPtr = actionListPtr->next;
325 deleteActionListItem( memPoolState, actionListItem );
326 }
327 ENSURES_V( iterationCount < FAILSAFE_ITERATIONS_MED );
328 }
329
330 /* Delete any orphaned actions, for example automatically-added hash actions
331 that were overridden by user-supplied alternate actions */
332
333 STDC_NONNULL_ARG( ( 1 ) ) \
deleteUnusedActions(INOUT ENVELOPE_INFO * envelopeInfoPtr)334 int deleteUnusedActions( INOUT ENVELOPE_INFO *envelopeInfoPtr )
335 {
336 ACTION_LIST *actionListPtr;
337 int iterationCount, status;
338
339 assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
340
341 /* Check for unattached encryption, hash/MAC, or generic-secret actions
342 and delete them */
343 for( actionListPtr = envelopeInfoPtr->actionList, iterationCount = 0;
344 actionListPtr != NULL && \
345 iterationCount < FAILSAFE_ITERATIONS_MED;
346 iterationCount++ )
347 {
348 ACTION_LIST *actionListCurrent = actionListPtr;
349
350 actionListPtr = actionListPtr->next;
351 if( ( actionListCurrent->action == ACTION_CRYPT || \
352 actionListCurrent->action == ACTION_HASH || \
353 actionListCurrent->action == ACTION_MAC || \
354 actionListCurrent->action == ACTION_xxx ) && \
355 ( actionListCurrent->flags & ACTION_NEEDSCONTROLLER ) )
356 {
357 status = deleteAction( &envelopeInfoPtr->actionList,
358 envelopeInfoPtr->memPoolState,
359 actionListCurrent );
360 if( cryptStatusError( status ) )
361 return( status );
362 }
363 }
364 ENSURES( iterationCount < FAILSAFE_ITERATIONS_MED );
365
366 return( CRYPT_OK );
367 }
368
369 /****************************************************************************
370 * *
371 * Check an Action *
372 * *
373 ****************************************************************************/
374
375 /* Check a new action to make sure that it isn't already present in the
376 action list, producing an ACTION_RESULT outcome */
377
CHECK_RETVAL_ENUM(ACTION)378 CHECK_RETVAL_ENUM( ACTION ) \
379 ACTION_RESULT checkAction( IN_OPT const ACTION_LIST *actionListStart,
380 IN_ENUM( ACTION ) const ACTION_TYPE actionType,
381 IN_HANDLE const CRYPT_HANDLE cryptHandle )
382 {
383 ACTION_LIST *actionListPtr = ( ACTION_LIST * ) actionListStart;
384 MESSAGE_DATA msgData;
385 BYTE keyID[ KEYID_SIZE + 8 ];
386 int algorithm DUMMY_INIT, iterationCount, status;
387
388 assert( actionListPtr == NULL || \
389 isReadPtr( actionListPtr, sizeof( ACTION_LIST ) ) );
390
391 REQUIRES_EXT( ( actionType == ACTION_KEYEXCHANGE_PKC || \
392 actionType == ACTION_KEYEXCHANGE || \
393 actionType == ACTION_CRYPT || \
394 actionType == ACTION_MAC || \
395 actionType == ACTION_HASH || \
396 actionType == ACTION_SIGN ), ACTION_RESULT_ERROR );
397 REQUIRES_EXT( isHandleRangeValid( cryptHandle ), ACTION_RESULT_ERROR );
398
399 /* If the action list is empty, there's nothing to check */
400 if( actionListPtr == NULL )
401 return( ACTION_RESULT_EMPTY );
402
403 /* Get identification information for the action object */
404 switch( actionType )
405 {
406 case ACTION_KEYEXCHANGE:
407 /* For conventional key wrap we can't really do much, for raw
408 action objects we'd check the algorithm for duplicates but
409 it's perfectly valid to wrap a single session/MAC key using
410 multiple key wrap objects with the same algorithm */
411 status = CRYPT_OK;
412 break;
413
414 case ACTION_KEYEXCHANGE_PKC:
415 case ACTION_SIGN:
416 /* It's a PKC object, get the key ID */
417 setMessageData( &msgData, keyID, KEYID_SIZE );
418 status = krnlSendMessage( cryptHandle, IMESSAGE_GETATTRIBUTE_S,
419 &msgData, CRYPT_IATTRIBUTE_KEYID );
420 break;
421
422 case ACTION_HASH:
423 case ACTION_MAC:
424 case ACTION_CRYPT:
425 /* It's a raw action object, get the algorithm */
426 status = krnlSendMessage( cryptHandle, IMESSAGE_GETATTRIBUTE,
427 &algorithm, CRYPT_CTXINFO_ALGO );
428 break;
429
430 default:
431 retIntError_Ext( ACTION_RESULT_ERROR );
432 }
433 if( cryptStatusError( status ) )
434 return( ACTION_RESULT_ERROR );
435
436 /* Walk down the list from the first to the last action in the action
437 group checking each one in turn */
438 for( actionListPtr = findAction( actionListPtr, actionType ), \
439 iterationCount = 0;
440 actionListPtr != NULL && actionListPtr->action == actionType && \
441 iterationCount < FAILSAFE_ITERATIONS_MED;
442 actionListPtr = actionListPtr->next, iterationCount++ )
443 {
444 BOOLEAN isDuplicate = FALSE;
445 int actionAlgo;
446
447 /* Make sure that we haven't added this action already. This can
448 get a bit tricky both because detecting some types of duplicates
449 is rather hard and because the definition of what's an invalid
450 duplicate varies somewhat. For a hash, MAC, and encryption
451 action we only allow one action of a given algorithm type to
452 be added. For a PKC key exchange or signature action we only
453 allow one action for a given key to be added. For a conventional
454 key exchange action we should in theory check for duplicates in
455 some form but it's not certain what constitutes a duplicate (for
456 example are two otherwise identical actions with a different
457 number of key setup iterations considered duplicates or not?) so
458 for now we assume that the user won't do anything silly (in any
459 case for any key exchange action the only thing that a duplicate
460 will do is result in unnecessary bloating of the envelope
461 header).
462
463 In addition to the more sophisticated checks we also perform a
464 few more basic ones for the same object being added twice, which
465 doesn't catch e.g. inadvertent use of the same keying material
466 but does catch simple programming errors */
467 if( actionListPtr->iCryptHandle == cryptHandle )
468 return( ACTION_RESULT_INITED );
469 switch( actionType )
470 {
471 case ACTION_KEYEXCHANGE:
472 /* It's a conventional key exchange, there's not much that
473 we can check */
474 break;
475
476 case ACTION_KEYEXCHANGE_PKC:
477 case ACTION_SIGN:
478 /* It's a PKC key exchange or signature action, compare the
479 two objects by comparing their keys */
480 setMessageData( &msgData, keyID, KEYID_SIZE );
481 if( cryptStatusOK( \
482 krnlSendMessage( actionListPtr->iCryptHandle,
483 IMESSAGE_COMPARE, &msgData,
484 MESSAGE_COMPARE_KEYID ) ) )
485 isDuplicate = TRUE;
486 break;
487
488 case ACTION_HASH:
489 case ACTION_MAC:
490 case ACTION_CRYPT:
491 /* It's a hash/MAC or session key object, compare the two
492 objects by comparing their algorithms */
493 if( cryptStatusOK( \
494 krnlSendMessage( actionListPtr->iCryptHandle,
495 IMESSAGE_GETATTRIBUTE, &actionAlgo,
496 CRYPT_CTXINFO_ALGO ) ) && \
497 actionAlgo == algorithm )
498 isDuplicate = TRUE;
499 break;
500
501 }
502 if( isDuplicate )
503 {
504 /* If the action was added automatically/implicitly as the
505 result of adding another action then the first attempt to add
506 it explicitly by the caller isn't an error. The caller will
507 treat the ACTION_RESULT_PRESENT code as CRYPT_OK */
508 if( actionListPtr->flags & ACTION_ADDEDAUTOMATICALLY )
509 {
510 actionListPtr->flags &= ~ACTION_ADDEDAUTOMATICALLY;
511 return( ACTION_RESULT_PRESENT );
512 }
513
514 return( ACTION_RESULT_INITED );
515 }
516 }
517 ENSURES_EXT( ( iterationCount < FAILSAFE_ITERATIONS_MED ), \
518 ACTION_RESULT_ERROR );
519
520 return( ACTION_RESULT_OK );
521 }
522
523 /* An indirect action-check function that uses a caller-supplied callback to
524 verify each action */
525
526 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
checkActionIndirect(const ACTION_LIST * actionListStart,IN CHECKACTION_FUNCTION checkActionFunction,IN_INT_Z const int intParam)527 int checkActionIndirect( const ACTION_LIST *actionListStart,
528 IN CHECKACTION_FUNCTION checkActionFunction,
529 IN_INT_Z const int intParam )
530 {
531 const ACTION_LIST *actionListPtr;
532 int iterationCount;
533
534 assert( isReadPtr( actionListStart, sizeof( ACTION_LIST ) ) );
535
536 REQUIRES( checkActionFunction != NULL );
537
538 for( actionListPtr = actionListStart, iterationCount = 0;
539 actionListPtr != NULL && iterationCount < FAILSAFE_ITERATIONS_MED;
540 actionListPtr = actionListPtr->next, iterationCount++ )
541 {
542 const int status = checkActionFunction( actionListPtr, intParam );
543 if( cryptStatusError( status ) )
544 return( status );
545 }
546 ENSURES( iterationCount < FAILSAFE_ITERATIONS_MED );
547
548 return( CRYPT_OK );
549 }
550
551 /* Perform a sanity-check to ensure that the actions in an envelope are
552 consistent. There are two approaches to this, take the envelope usage
553 and check that everything is consistent with it, or take the actions
554 and make sure that they're consistent with the usage (and each other).
555 We perform the latter type of check, which is somewhat simpler. The
556 requirements that we enforce are:
557
558 | Pre | In | Post |
559 --------+-----------+-----------+-----------+-----
560 SIG | - | Hash | Sig | CMS
561 | - | 1x Hash | 1x Sig | PGP
562 --------+-----------+-----------+-----------+-----
563 MAC | Keyex,PKC | 1x MAC | - | CMS
564 | - | - | - | PGP
565 --------+-----------+-----------+-----------+-----
566 COPR | - | - | - | CMS
567 | - | - | - | PGP
568 --------+-----------+-----------+-----------+-----
569 ENCR | Keyex,PKC | Crypt | - | CMS
570 | PKC | 1x Crypt | - | PGP
571
572 In the case of ENCR the pre-actions can be absent if we're using raw
573 session-key encryption */
574
575 CHECK_RETVAL_BOOL STDC_NONNULL_ARG( ( 1 ) ) \
checkActions(INOUT ENVELOPE_INFO * envelopeInfoPtr)576 BOOLEAN checkActions( INOUT ENVELOPE_INFO *envelopeInfoPtr )
577 {
578 ACTION_LIST *actionListPtr;
579 int iterationCount;
580
581 assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
582
583 /* If there are no pre-, post-, or main actions (i.e. it's a compressed
584 or data-only envelope), we're done */
585 if( envelopeInfoPtr->actionList == NULL )
586 {
587 /* Make sure that the envelope has the appropriate usage for these
588 actions */
589 if( envelopeInfoPtr->usage != ACTION_COMPRESS && \
590 envelopeInfoPtr->usage != ACTION_NONE )
591 return( FALSE );
592
593 /* There can be no pre- or post-actions present for this usage */
594 if( envelopeInfoPtr->preActionList != NULL || \
595 envelopeInfoPtr->postActionList != NULL )
596 return( FALSE );
597
598 return( TRUE );
599 }
600
601 /* If there are pre-actions it has to be a key exchange followed by
602 encryption or MAC actions */
603 if( envelopeInfoPtr->preActionList != NULL )
604 {
605 int cryptActionCount = 0, macActionCount = 0;
606 int genericSecretActionCount = 0;
607
608 /* Make sure that the envelope has the appropriate usage for these
609 actions */
610 if( envelopeInfoPtr->usage != ACTION_CRYPT && \
611 envelopeInfoPtr->usage != ACTION_MAC )
612 return( FALSE );
613
614 /* If there's a pre-action then there has to be a main action
615 list */
616 if( envelopeInfoPtr->actionList == NULL )
617 return( FALSE );
618
619 /* Pre-actions can only be key exchange actions and have to be sorted
620 by action group */
621 for( actionListPtr = envelopeInfoPtr->preActionList, \
622 iterationCount = 0;
623 actionListPtr != NULL && \
624 actionListPtr->action == ACTION_KEYEXCHANGE_PKC && \
625 iterationCount < FAILSAFE_ITERATIONS_MED;
626 actionListPtr = actionListPtr->next, iterationCount++ );
627 ENSURES_B( iterationCount < FAILSAFE_ITERATIONS_MED );
628 if( envelopeInfoPtr->type == CRYPT_FORMAT_PGP && \
629 actionListPtr != NULL )
630 {
631 /* PGP can't have any conventional keyex actions since the
632 password is used to directly derive the session key */
633 return( FALSE );
634 }
635 for( iterationCount = 0;
636 actionListPtr != NULL && \
637 actionListPtr->action == ACTION_KEYEXCHANGE && \
638 iterationCount < FAILSAFE_ITERATIONS_MED;
639 actionListPtr = actionListPtr->next, iterationCount++ );
640 ENSURES_B( iterationCount < FAILSAFE_ITERATIONS_MED );
641 if( actionListPtr != NULL )
642 return( FALSE );
643 ENSURES_B( envelopeInfoPtr->actionList != NULL );
644
645 /* PGP only supports an encryption action followed by an optional
646 hash action for encryption with MDC */
647 if( envelopeInfoPtr->type == CRYPT_FORMAT_PGP )
648 {
649 actionListPtr = envelopeInfoPtr->actionList;
650 if( actionListPtr->action != ACTION_CRYPT )
651 return( FALSE );
652 if( actionListPtr->next != NULL )
653 {
654 actionListPtr = actionListPtr->next;
655 if( actionListPtr->action != ACTION_HASH || \
656 actionListPtr->next != NULL )
657 return( FALSE );
658 }
659
660 /* There can't be any post-actions */
661 if( envelopeInfoPtr->postActionList != NULL )
662 return( FALSE );
663
664 return( TRUE );
665 }
666
667 /* Key exchange must be followed by a single crypt, one or more
668 MAC actions, or a sequence of { generic-secret, crypt, MAC }
669 actions. First we count the actions present */
670 for( actionListPtr = envelopeInfoPtr->actionList, iterationCount = 0;
671 actionListPtr != NULL && \
672 iterationCount < FAILSAFE_ITERATIONS_MED;
673 actionListPtr = actionListPtr->next, iterationCount++ )
674 {
675 switch( actionListPtr->action )
676 {
677 case ACTION_xxx:
678 genericSecretActionCount++;
679 break;
680
681 case ACTION_CRYPT:
682 cryptActionCount++;
683 break;
684
685 case ACTION_MAC:
686 macActionCount++;
687 break;
688
689 default:
690 return( FALSE );
691 }
692 }
693 ENSURES_B( iterationCount < FAILSAFE_ITERATIONS_MED );
694
695 /* Then we make sure that what's present follows the requirements
696 given above */
697 if( genericSecretActionCount > 0 )
698 {
699 /* AuthEnc envelope, we need a sequence of { generic-secret,
700 crypt, MAC } */
701 if( genericSecretActionCount != 1 || \
702 cryptActionCount != 1 || macActionCount != 1 )
703 return( FALSE );
704 }
705 else
706 {
707 if( cryptActionCount > 0 )
708 {
709 /* Encrypted envelope, we need a single encryption action */
710 if( cryptActionCount > 1 || \
711 genericSecretActionCount != 0 || macActionCount != 0 )
712 return( FALSE );
713 }
714 else
715 {
716 /* MACed envelope, we need one or more MAC actions (the check
717 for genericSecretActionCount is redudant since we already
718 know that it's 0, but it's included here to document the
719 required condition) */
720 if( genericSecretActionCount != 0 || cryptActionCount != 0 )
721 return( FALSE );
722 }
723 }
724
725 /* There can't be any post-actions */
726 if( envelopeInfoPtr->postActionList != NULL )
727 return( FALSE );
728
729 return( TRUE );
730 }
731
732 /* If there are post-actions it has to be a hash follwed by signature
733 actions */
734 if( envelopeInfoPtr->postActionList != NULL )
735 {
736 int hashActionCount = 0, sigActionCount = 0;
737
738 /* Make sure that the envelope has the appropriate usage for these
739 actions */
740 if( envelopeInfoPtr->usage != ACTION_SIGN )
741 return( FALSE );
742
743 /* There can't be any pre-actions */
744 if( envelopeInfoPtr->preActionList != NULL )
745 return( FALSE );
746
747 /* The signature must be preceded by one or more hash actions */
748 if( envelopeInfoPtr->actionList == NULL )
749 return( FALSE );
750 for( actionListPtr = envelopeInfoPtr->actionList, iterationCount = 0;
751 actionListPtr != NULL && \
752 iterationCount < FAILSAFE_ITERATIONS_MED;
753 actionListPtr = actionListPtr->next, iterationCount++ )
754 {
755 if( actionListPtr->action != ACTION_HASH )
756 return( FALSE );
757 hashActionCount++;
758 }
759 ENSURES_B( iterationCount < FAILSAFE_ITERATIONS_MED );
760
761 /* PGP can only have a single hash per signed envelope */
762 if( envelopeInfoPtr->type == CRYPT_FORMAT_PGP && hashActionCount > 1 )
763 return( FALSE );
764
765 /* Hash actions must be followed by one or more signature actions */
766 for( actionListPtr = envelopeInfoPtr->postActionList, \
767 iterationCount = 0;
768 actionListPtr != NULL && \
769 iterationCount < FAILSAFE_ITERATIONS_MED;
770 actionListPtr = actionListPtr->next, iterationCount++ )
771 {
772 if( actionListPtr->action != ACTION_SIGN )
773 return( FALSE );
774 sigActionCount++;
775 }
776 ENSURES_B( iterationCount < FAILSAFE_ITERATIONS_MED );
777
778 /* PGP can only have a single signature, multiple signatures are
779 handled by nesting envelopes */
780 if( envelopeInfoPtr->type == CRYPT_FORMAT_PGP && sigActionCount > 1 )
781 return( FALSE );
782
783 return( TRUE );
784 }
785
786 /* If there's a standalone session-key encryption action, it has to be
787 the only action present */
788 actionListPtr = envelopeInfoPtr->actionList;
789 ENSURES_B( actionListPtr != NULL );
790 if( actionListPtr->action == ACTION_CRYPT )
791 {
792 /* Make sure that the envelope has the appropriate usage for these
793 actions */
794 if( envelopeInfoPtr->usage != ACTION_CRYPT )
795 return( FALSE );
796
797 /* If we're performing authenticated encryption then the encryption
798 action has to be followed by a MAC action (CMS) or a hash action
799 (PGP, which is encrypted and sort-of keyed so it's a sort-of
800 MAC) */
801 if( envelopeInfoPtr->flags & ENVELOPE_AUTHENC )
802 {
803 const ACTION_TYPE requiredActionType = \
804 ( envelopeInfoPtr->type == CRYPT_FORMAT_PGP ) ? \
805 ACTION_HASH : ACTION_MAC;
806
807 actionListPtr = actionListPtr->next;
808 if( actionListPtr == NULL || \
809 actionListPtr->action != requiredActionType || \
810 actionListPtr->next != NULL )
811 return( FALSE );
812
813 return( TRUE );
814 }
815
816 /* PGP can optionally follow an encryption action with a hash action
817 for encryption with MDC */
818 if( envelopeInfoPtr->type == CRYPT_FORMAT_PGP && \
819 actionListPtr->next != NULL )
820 {
821 actionListPtr = actionListPtr->next;
822 if( actionListPtr->action != ACTION_HASH || \
823 actionListPtr->next != NULL )
824 return( FALSE );
825
826 return( TRUE );
827 }
828
829 /* There can only be one encryption action present */
830 if( actionListPtr->next != NULL )
831 return( FALSE );
832
833 return( TRUE );
834 }
835
836 /* If we're processing PGP-encrypted data with an MDC at the end of the
837 encrypted data then it's possible to have an encryption envelope with
838 a hash action (which must be followed by an encryption action) */
839 if( envelopeInfoPtr->type == CRYPT_FORMAT_PGP && \
840 actionListPtr->action == ACTION_HASH && \
841 actionListPtr->next != NULL && \
842 actionListPtr->next->action == ACTION_CRYPT )
843 {
844 ACTION_LIST *nextActionPtr = actionListPtr->next;
845
846 /* Make sure that the envelope has the appropriate usage for these
847 actions */
848 if( envelopeInfoPtr->usage != ACTION_CRYPT )
849 return( FALSE );
850
851 /* Make sure that the encryption action is the only other action */
852 if( nextActionPtr->action != ACTION_CRYPT || \
853 nextActionPtr->next != NULL )
854 return( FALSE );
855
856 return( TRUE );
857 }
858
859 /* If it's a MACd envelope then there can only be a single MAC action
860 present */
861 if( envelopeInfoPtr->usage == ACTION_MAC )
862 {
863 /* Make sure that there's only a single MAC action present */
864 if( actionListPtr->action != ACTION_MAC || \
865 actionListPtr->next != NULL )
866 return( FALSE );
867
868 return( TRUE );
869 }
870
871 /* Anything else has to be a signing envelope */
872 if( envelopeInfoPtr->usage != ACTION_SIGN )
873 return( FALSE );
874
875 /* When we're de-enveloping a signed envelope we can have standalone
876 hash actions before we get to the signature data and add post-
877 actions */
878 if( ( envelopeInfoPtr->flags & ENVELOPE_ISDEENVELOPE ) && \
879 actionListPtr->action == ACTION_HASH )
880 {
881 for( iterationCount = 0; \
882 actionListPtr != NULL && \
883 iterationCount < FAILSAFE_ITERATIONS_MED;
884 actionListPtr = actionListPtr->next, iterationCount++ )
885 {
886 if( actionListPtr->action != ACTION_HASH )
887 return( FALSE );
888 }
889 ENSURES_B( iterationCount < FAILSAFE_ITERATIONS_MED );
890
891 return( TRUE );
892 }
893
894 /* Everything else is an error */
895 return( FALSE );
896 }
897 #endif /* USE_ENVELOPES */
898