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