1 /****************************************************************************
2 *																			*
3 *					cryptlib De-enveloping Information Management			*
4 *						Copyright Peter Gutmann 1996-2013					*
5 *																			*
6 ****************************************************************************/
7 
8 #if defined( INC_ALL )
9   #include "asn1.h"
10   #include "asn1_ext.h"
11   #include "envelope.h"
12   #include "pgp.h"
13 #else
14   #include "enc_dec/asn1.h"
15   #include "enc_dec/asn1_ext.h"
16   #include "envelope/envelope.h"
17   #include "misc/pgp.h"
18 #endif /* Compiler-specific includes */
19 
20 /* The maximum number of content items that we can add to a content list.
21    We should use FAILSAFE_ITERATIONS_MED but encrypted messages sent to very
22    large distribution lists can have a number of per-recipient wrapped keys
23    that exceed this value */
24 
25 #define MAX_CONTENT_ITEMS	FAILSAFE_ITERATIONS_LARGE - 1
26 
27 #ifdef USE_ENVELOPES
28 
29 /****************************************************************************
30 *																			*
31 *						Content List Management Functions					*
32 *																			*
33 ****************************************************************************/
34 
35 /* Check whether more content items can be added to a content list */
36 
37 CHECK_RETVAL_BOOL \
moreContentItemsPossible(IN_OPT const CONTENT_LIST * contentListPtr)38 BOOLEAN moreContentItemsPossible( IN_OPT const CONTENT_LIST *contentListPtr )
39 	{
40 	int contentListCount;
41 
42 	assert( contentListPtr == NULL || \
43 			isReadPtr( contentListPtr, sizeof( ACTION_LIST ) ) );
44 
45 	for( contentListCount = 0;
46 		 contentListPtr != NULL && contentListCount < FAILSAFE_ITERATIONS_LARGE;
47 		 contentListPtr = contentListPtr->next, contentListCount++ );
48 	ENSURES_B( contentListCount < FAILSAFE_ITERATIONS_LARGE );
49 
50 	return( ( contentListCount < MAX_CONTENT_ITEMS ) ? TRUE : FALSE );
51 	}
52 
53 /* Create a content list item */
54 
55 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
createContentListItem(OUT_BUFFER_ALLOC_OPT (sizeof (CONTENT_LIST))CONTENT_LIST ** newContentListItemPtrPtr,INOUT MEMPOOL_STATE memPoolState,IN_ENUM (CONTENT)const CONTENT_TYPE type,IN_ENUM (CRYPT_FORMAT)const CRYPT_FORMAT_TYPE formatType,IN_BUFFER_OPT (objectSize)const void * object,IN_LENGTH_Z const int objectSize)56 int createContentListItem( OUT_BUFFER_ALLOC_OPT( sizeof( CONTENT_LIST ) ) \
57 								CONTENT_LIST **newContentListItemPtrPtr,
58 						   INOUT MEMPOOL_STATE memPoolState,
59 						   IN_ENUM( CONTENT ) const CONTENT_TYPE type,
60 						   IN_ENUM( CRYPT_FORMAT ) \
61 								const CRYPT_FORMAT_TYPE formatType,
62 						   IN_BUFFER_OPT( objectSize ) const void *object,
63 						   IN_LENGTH_Z const int objectSize )
64 	{
65 	CONTENT_LIST *newItem;
66 
67 	assert( isWritePtr( newContentListItemPtrPtr, \
68 						sizeof( CONTENT_LIST * ) ) );
69 	assert( isWritePtr( memPoolState, sizeof( MEMPOOL_STATE ) ) );
70 	assert( objectSize == 0 || isReadPtr( object, objectSize ) );
71 
72 	REQUIRES( type > CONTENT_NONE && type < CONTENT_LAST );
73 	REQUIRES( formatType > CRYPT_FORMAT_NONE && \
74 			  formatType < CRYPT_FORMAT_LAST );
75 	REQUIRES( ( object == NULL && objectSize == 0 ) || \
76 			  ( object != NULL && \
77 				objectSize > 0 && objectSize < MAX_BUFFER_SIZE ) );
78 
79 	/* Clear return value */
80 	*newContentListItemPtrPtr = NULL;
81 
82 	if( ( newItem = getMemPool( memPoolState, \
83 								sizeof( CONTENT_LIST ) ) ) == NULL )
84 		return( CRYPT_ERROR_MEMORY );
85 	memset( newItem, 0, sizeof( CONTENT_LIST ) );
86 	newItem->type = type;
87 	newItem->formatType = formatType;
88 	newItem->object = object;
89 	newItem->objectSize = objectSize;
90 	if( type == CONTENT_SIGNATURE )
91 		{
92 		newItem->clSigInfo.iSigCheckKey = CRYPT_ERROR;
93 		newItem->clSigInfo.iExtraData = CRYPT_ERROR;
94 		newItem->clSigInfo.iTimestamp = CRYPT_ERROR;
95 		}
96 	*newContentListItemPtrPtr = newItem;
97 
98 	return( CRYPT_OK );
99 	}
100 
101 /* Add an item to the content list */
102 
103 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
appendContentListItem(INOUT ENVELOPE_INFO * envelopeInfoPtr,INOUT CONTENT_LIST * contentListItem)104 int appendContentListItem( INOUT ENVELOPE_INFO *envelopeInfoPtr,
105 						   INOUT CONTENT_LIST *contentListItem )
106 	{
107 	CONTENT_LIST *contentListPtr = envelopeInfoPtr->contentList;
108 
109 	assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
110 	assert( contentListPtr == NULL || \
111 			isWritePtr( contentListPtr, sizeof( CONTENT_LIST ) ) );
112 
113 	/* Find the end of the list and add the new item */
114 	if( contentListPtr != NULL )
115 		{
116 		int iterationCount = 0;
117 
118 		for( contentListPtr = envelopeInfoPtr->contentList, \
119 				iterationCount = 0;
120 			 contentListPtr->next != NULL && \
121 			   iterationCount < FAILSAFE_ITERATIONS_LARGE;
122 			contentListPtr = contentListPtr->next, iterationCount++ );
123 		ENSURES( iterationCount < FAILSAFE_ITERATIONS_LARGE );
124 		}
125 	insertDoubleListElements( &envelopeInfoPtr->contentList, contentListPtr,
126 							  contentListItem, contentListItem );
127 
128 	return( CRYPT_OK );
129 	}
130 
131 /* Delete a content list */
132 
133 STDC_NONNULL_ARG( ( 1, 2 ) ) \
deleteContentList(INOUT MEMPOOL_STATE memPoolState,INOUT_PTR CONTENT_LIST ** contentListHeadPtrPtr)134 int deleteContentList( INOUT MEMPOOL_STATE memPoolState,
135 					   INOUT_PTR CONTENT_LIST **contentListHeadPtrPtr )
136 	{
137 	CONTENT_LIST *contentListCursor;
138 	int iterationCount;
139 
140 	assert( isWritePtr( memPoolState, sizeof( MEMPOOL_STATE ) ) );
141 	assert( isWritePtr( contentListHeadPtrPtr, sizeof( CONTENT_LIST * ) ) );
142 
143 	for( contentListCursor = *contentListHeadPtrPtr, iterationCount = 0;
144 		 contentListCursor != NULL && \
145 			iterationCount < FAILSAFE_ITERATIONS_LARGE;
146 		 iterationCount++ )
147 		{
148 		CONTENT_LIST *contentListItem = contentListCursor;
149 
150 		contentListCursor = contentListCursor->next;
151 
152 		/* Destroy any attached objects if necessary */
153 		if( contentListItem->type == CONTENT_SIGNATURE )
154 			{
155 			CONTENT_SIG_INFO *sigInfo = &contentListItem->clSigInfo;
156 
157 			if( sigInfo->iSigCheckKey != CRYPT_ERROR )
158 				krnlSendNotifier( sigInfo->iSigCheckKey, IMESSAGE_DECREFCOUNT );
159 			if( sigInfo->iExtraData != CRYPT_ERROR )
160 				krnlSendNotifier( sigInfo->iExtraData, IMESSAGE_DECREFCOUNT );
161 			if( sigInfo->iTimestamp != CRYPT_ERROR )
162 				krnlSendNotifier( sigInfo->iTimestamp, IMESSAGE_DECREFCOUNT );
163 			}
164 
165 		/* Erase and free the object buffer if necessary */
166 		deleteDoubleListElement( contentListHeadPtrPtr, contentListItem );
167 		if( contentListItem->object != NULL )
168 			{
169 			void *contentPtr = ( void * ) contentListItem->object;
170 				 /* Although the data is declared 'const' since it can't be
171 					modified, we still have to be able to zeroise it on free
172 					so we override the const for this */
173 
174 			zeroise( contentPtr, contentListItem->objectSize );
175 			clFree( "deleteContentList", contentPtr );
176 			}
177 		zeroise( contentListItem, sizeof( CONTENT_LIST ) );
178 		freeMemPool( memPoolState, contentListItem );
179 		}
180 	ENSURES( iterationCount < FAILSAFE_ITERATIONS_LARGE );
181 
182 	*contentListHeadPtrPtr = NULL;
183 
184 	return( CRYPT_OK );
185 	}
186 
187 /****************************************************************************
188 *																			*
189 *							Process Signature Data 							*
190 *																			*
191 ****************************************************************************/
192 
193 /* Process timestamps */
194 
195 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
processTimestamp(INOUT CONTENT_LIST * contentListPtr,IN_BUFFER (timestampLength)const void * timestamp,IN_LENGTH_MIN (MIN_CRYPT_OBJECTSIZE)const int timestampLength)196 static int processTimestamp( INOUT CONTENT_LIST *contentListPtr,
197 							 IN_BUFFER( timestampLength ) const void *timestamp,
198 							 IN_LENGTH_MIN( MIN_CRYPT_OBJECTSIZE ) \
199 								const int timestampLength )
200 	{
201 	CRYPT_ENVELOPE iTimestampEnvelope;
202 	MESSAGE_CREATEOBJECT_INFO createInfo;
203 	MESSAGE_DATA msgData;
204 	const int bufSize = max( timestampLength + 128, MIN_BUFFER_SIZE );
205 	int status;
206 
207 	assert( isWritePtr( contentListPtr, sizeof( CONTENT_LIST ) ) );
208 	assert( isReadPtr( timestamp, timestampLength ) );
209 
210 	REQUIRES( timestampLength >= MIN_CRYPT_OBJECTSIZE && \
211 			  timestampLength < MAX_BUFFER_SIZE );
212 
213 	/* Create an envelope to contain the timestamp data.  We can't use the
214 	   internal enveloping API for this because we want to retain the final
215 	   envelope and not just recover the data contents (which for a
216 	   timestamp will be empty anyway) */
217 	setMessageCreateObjectInfo( &createInfo, CRYPT_FORMAT_AUTO );
218 	status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_DEV_CREATEOBJECT,
219 							  &createInfo, OBJECT_TYPE_ENVELOPE );
220 	if( cryptStatusError( status ) )
221 		return( status );
222 	iTimestampEnvelope = createInfo.cryptHandle;
223 
224 	/* Push in the timestamp data */
225 	status = krnlSendMessage( iTimestampEnvelope, IMESSAGE_SETATTRIBUTE,
226 							  ( MESSAGE_CAST ) &bufSize,
227 							  CRYPT_ATTRIBUTE_BUFFERSIZE );
228 	if( cryptStatusOK( status ) )
229 		{
230 		setMessageData( &msgData, ( MESSAGE_CAST ) timestamp, \
231 						timestampLength );
232 		status = krnlSendMessage( iTimestampEnvelope, IMESSAGE_ENV_PUSHDATA,
233 								  &msgData, 0 );
234 		}
235 	if( cryptStatusOK( status ) )
236 		{
237 		setMessageData( &msgData, NULL, 0 );
238 		status = krnlSendMessage( iTimestampEnvelope, IMESSAGE_ENV_PUSHDATA,
239 								  &msgData, 0 );
240 		}
241 	if( cryptStatusError( status ) )
242 		{
243 		krnlSendNotifier( iTimestampEnvelope, IMESSAGE_DECREFCOUNT );
244 		return( status );
245 		}
246 
247 	/* We've got the timestamp info in a sub-envelope, remember it for
248 	   later */
249 	contentListPtr->clSigInfo.iTimestamp = iTimestampEnvelope;
250 	return( CRYPT_OK );
251 	}
252 
253 /* Process CMS unauthenticated attributes.  We can't handle these as
254    standard CMS attributes since the only thing that we're likely to see
255    here is a countersignature, which isn't an attribute in the normal
256    sense */
257 
258 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
processUnauthAttributes(INOUT CONTENT_LIST * contentListPtr,IN_BUFFER (unauthAttrLength)const void * unauthAttr,IN_LENGTH_MIN (MIN_CRYPT_OBJECTSIZE)const int unauthAttrLength)259 static int processUnauthAttributes( INOUT CONTENT_LIST *contentListPtr,
260 									IN_BUFFER( unauthAttrLength ) \
261 										const void *unauthAttr,
262 									IN_LENGTH_MIN( MIN_CRYPT_OBJECTSIZE ) \
263 										const int unauthAttrLength )
264 	{
265 	STREAM stream;
266 	int iterationCount, status;
267 
268 	assert( isWritePtr( contentListPtr, sizeof( CONTENT_LIST ) ) );
269 	assert( isReadPtr( unauthAttr, unauthAttrLength ) );
270 
271 	REQUIRES( unauthAttrLength >= MIN_CRYPT_OBJECTSIZE && \
272 			  unauthAttrLength < MAX_BUFFER_SIZE );
273 
274 	/* Make sure that the unauthenticated attributes are OK.  Normally this
275 	   is done when we import the attributes but since we can't import
276 	   them we have to perform the check explicitly here */
277 	if( cryptStatusError( checkObjectEncoding( unauthAttr,
278 											   unauthAttrLength ) ) )
279 		return( CRYPT_ERROR_BADDATA );
280 
281 	/* Process each attribute */
282 	sMemConnect( &stream, unauthAttr, unauthAttrLength );
283 	status = readConstructed( &stream, NULL, 1 );
284 	for( iterationCount = 0;
285 		 cryptStatusOK( status ) && \
286 			sMemDataLeft( &stream ) >= MIN_CRYPT_OBJECTSIZE && \
287 			iterationCount < FAILSAFE_ITERATIONS_LARGE;
288 		 iterationCount++ )
289 		{
290 		BYTE oid[ MAX_OID_SIZE + 8 ];
291 		void *dataPtr;
292 		int oidLength, length DUMMY_INIT;
293 
294 		/* See what we've got */
295 		readSequence( &stream, NULL );
296 		status = readEncodedOID( &stream, oid, MAX_OID_SIZE, &oidLength,
297 								 BER_OBJECT_IDENTIFIER );
298 		if( cryptStatusOK( status ) )
299 			status = readSet( &stream, &length );
300 		if( cryptStatusError( status ) )
301 			break;
302 
303 		/* If it's something that we don't recognise, skip it and continue */
304 		if( oidLength != sizeofOID( OID_TSP_TSTOKEN ) || \
305 			memcmp( oid, OID_TSP_TSTOKEN, oidLength ) )
306 			{
307 			status = readUniversal( &stream );
308 			continue;
309 			}
310 
311 		/* We've got a timestamp.  We can't really do much with this at the
312 		   moment since although it quacks like a countersignature, in the
313 		   PKIX tradition it's subtly (and gratuitously) incompatible in
314 		   various ways so that it can't be verified as a standard
315 		   countersignature (video meliora proboque deteriora sequor).
316 		   Amusingly, the RFC actually states that this is a stupid way to
317 		   do things.  Specifically, instead of using the normal MUST/SHOULD
318 		   it first states that the sensible solution to the problem is to
319 		   use a countersignature, and then goes on to mandate something
320 		   that isn't a countersignature.  Since this isn't the sensible
321 		   solution, it's obviously the stupid one.  QED */
322 		if( length < MIN_CRYPT_OBJECTSIZE )
323 			{
324 			/* It's too short to be a valid timestamp */
325 			status = CRYPT_ERROR_UNDERFLOW;
326 			continue;
327 			}
328 		status = sMemGetDataBlock( &stream, &dataPtr, length );
329 		if( cryptStatusOK( status ) )
330 			status = sSkip( &stream, length, MAX_INTLENGTH_SHORT );
331 		if( cryptStatusOK( status ) )
332 			status = processTimestamp( contentListPtr, dataPtr, length );
333 		/* Continue in the loop with the cryptStatusOK() check */
334 		}
335 	ENSURES( iterationCount < FAILSAFE_ITERATIONS_LARGE );
336 	sMemDisconnect( &stream );
337 
338 	return( status );
339 	}
340 
341 /* Perform additional checks beyond those performed for a standard
342    signature as required by CMS signatures */
343 
344 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 5 ) ) \
checkCmsSignatureInfo(INOUT CONTENT_LIST * contentListPtr,IN_HANDLE const CRYPT_HANDLE iHashContext,IN_HANDLE const CRYPT_HANDLE iSigCheckContext,IN_ENUM (CRYPT_CONTENT)const CRYPT_CONTENT_TYPE contentType,INOUT ERROR_INFO * errorInfo)345 static int checkCmsSignatureInfo( INOUT CONTENT_LIST *contentListPtr,
346 								  IN_HANDLE const CRYPT_HANDLE iHashContext,
347 								  IN_HANDLE const CRYPT_HANDLE iSigCheckContext,
348 								  IN_ENUM( CRYPT_CONTENT ) \
349 									const CRYPT_CONTENT_TYPE contentType,
350 								  INOUT ERROR_INFO *errorInfo )
351 	{
352 	CONTENT_SIG_INFO *sigInfo = &contentListPtr->clSigInfo;
353 	int status;
354 
355 	assert( isWritePtr( contentListPtr, sizeof( CONTENT_LIST ) ) );
356 	assert( isWritePtr( errorInfo, sizeof( ENVELOPE_INFO ) ) );
357 
358 	REQUIRES( isHandleRangeValid( iHashContext ) );
359 	REQUIRES( isHandleRangeValid( iSigCheckContext ) );
360 	REQUIRES( contentType > CRYPT_CONTENT_NONE && \
361 			  contentType < CRYPT_CONTENT_LAST );
362 
363 	/* If it's CMS signed data then the signature check key should be
364 	   included with the signed data as a certificate chain, however it's
365 	   possible (though unlikely) that the certificates may be unrelated to
366 	   the signature, in which case the caller will have provided the
367 	   signature check key from an external source */
368 	status = iCryptCheckSignature( contentListPtr->object,
369 								   contentListPtr->objectSize,
370 								   CRYPT_FORMAT_CMS,
371 								   ( sigInfo->iSigCheckKey == CRYPT_ERROR ) ? \
372 									iSigCheckContext : sigInfo->iSigCheckKey,
373 								   iHashContext, CRYPT_UNUSED,
374 								   &sigInfo->iExtraData );
375 	if( cryptStatusError( status ) )
376 		{
377 		retExt( status,
378 				( status, errorInfo, "Signature verification failed" ) );
379 		}
380 
381 	/* If there are authenticated attributes present we have to perform an
382 	   extra check to make sure that the content-type specified in the
383 	   authenticated attributes matches the actual data content type */
384 	if( sigInfo->iExtraData != CRYPT_ERROR )
385 		{
386 		int signatureContentType;
387 
388 		status = krnlSendMessage( sigInfo->iExtraData, IMESSAGE_GETATTRIBUTE,
389 								  &signatureContentType,
390 								  CRYPT_CERTINFO_CMS_CONTENTTYPE );
391 		if( cryptStatusError( status ) || \
392 			signatureContentType != contentType )
393 			{
394 			retExt( CRYPT_ERROR_SIGNATURE,
395 					( CRYPT_ERROR_SIGNATURE, errorInfo,
396 					  "Content-type in authenticated attributes doesn't "
397 					  "match actual content type" ) );
398 			}
399 		}
400 
401 	/* If there are unauthenticated attributes present, process them.  We
402 	   don't record the processing status for these to ensure that some
403 	   random error in the non signature-related attributes doesn't
404 	   invalidate an otherwise OK signature */
405 	if( sigInfo->extraData2 != NULL )
406 		{
407 		const int localStatus = \
408 				processUnauthAttributes( contentListPtr, sigInfo->extraData2,
409 										 sigInfo->extraData2Length );
410 		if( cryptStatusError( localStatus ) )
411 			{
412 			retExt( CRYPT_ERROR_BADDATA,
413 					( CRYPT_ERROR_BADDATA, errorInfo,
414 					  "Invalid unauthenticated attribute data") );
415 			}
416 		}
417 
418 	return( CRYPT_OK );
419 	}
420 
421 /****************************************************************************
422 *																			*
423 *							Process Encryption Data							*
424 *																			*
425 ****************************************************************************/
426 
427 /* Add a new encryption or MAC action to the envelope's action list */
428 
429 CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
addActionToList(INOUT ENVELOPE_INFO * envelopeInfoPtr,IN_HANDLE const CRYPT_CONTEXT iCryptContext,IN_ENUM (ACTION)const ACTION_TYPE action)430 static int addActionToList( INOUT ENVELOPE_INFO *envelopeInfoPtr,
431 							IN_HANDLE const CRYPT_CONTEXT iCryptContext,
432 							IN_ENUM( ACTION ) const ACTION_TYPE action )
433 	{
434 	ACTION_RESULT actionResult;
435 
436 	assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
437 
438 	REQUIRES( isHandleRangeValid( iCryptContext ) );
439 	REQUIRES( action == ACTION_CRYPT || action == ACTION_MAC );
440 
441 	/* Add the action to the envelope action list */
442 	actionResult = checkAction( envelopeInfoPtr->actionList, action,
443 								iCryptContext );
444 	if( actionResult == ACTION_RESULT_ERROR || \
445 		actionResult == ACTION_RESULT_INITED )
446 		return( CRYPT_ERROR_INITED );
447 	return( addAction( &envelopeInfoPtr->actionList,
448 					   envelopeInfoPtr->memPoolState, action,
449 					   iCryptContext ) );
450 	}
451 
452 /* Initialise a recovered encryption key, either directly if it's a session
453    key or indirectly if it's a generic-secret key used to derive encryption
454    and MAC contexts and keys */
455 
456 CHECK_RETVAL_SPECIAL STDC_NONNULL_ARG( ( 1, 3, 4 ) ) \
initKeys(INOUT ENVELOPE_INFO * envelopeInfoPtr,IN_HANDLE const CRYPT_CONTEXT iSessionKeyContext,OUT_HANDLE_OPT CRYPT_CONTEXT * iCryptContext,OUT_HANDLE_OPT CRYPT_CONTEXT * iMacContext)457 static int initKeys( INOUT ENVELOPE_INFO *envelopeInfoPtr,
458 					 IN_HANDLE const CRYPT_CONTEXT iSessionKeyContext,
459 					 OUT_HANDLE_OPT CRYPT_CONTEXT *iCryptContext,
460 					 OUT_HANDLE_OPT CRYPT_CONTEXT *iMacContext )
461 	{
462 	CRYPT_CONTEXT iAuthEncCryptContext, iAuthEncMacContext;
463 	CRYPT_ALGO_TYPE kdfAlgo DUMMY_INIT;
464 	const CONTENT_LIST *contentListPtr;
465 	const CONTENT_ENCR_INFO *encrInfo;
466 	const CONTENT_AUTHENC_INFO *authEncInfo;
467 	MECHANISM_KDF_INFO mechanismInfo;
468 	CONTENT_ENCR_INFO localEncrInfo;
469 	STREAM stream;
470 	int value, kdfAlgoParam DUMMY_INIT, iterationCount, status;
471 
472 	assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
473 	assert( isWritePtr( iCryptContext, sizeof( CRYPT_CONTEXT ) ) );
474 	assert( isWritePtr( iMacContext, sizeof( CRYPT_CONTEXT ) ) );
475 
476 	REQUIRES( isHandleRangeValid( iSessionKeyContext ) );
477 
478 	/* Clear return values.  Note that we set the returned context to the
479 	   passed-in context since this is the default (identity) transformation,
480 	   it's only when using authenticated encryption that it gets set to a
481 	   new context */
482 	*iCryptContext = iSessionKeyContext;
483 	*iMacContext = CRYPT_ERROR;
484 
485 	/* Check whether we got as far as the encrypted data, which will be
486 	   indicated by the fact that there's content information present from
487 	   which we can set up the decryption */
488 	for( contentListPtr = envelopeInfoPtr->contentList, iterationCount = 0;
489 		 contentListPtr != NULL && \
490 			contentListPtr->envInfo != CRYPT_ENVINFO_SESSIONKEY && \
491 			iterationCount < FAILSAFE_ITERATIONS_LARGE;
492 		 contentListPtr = contentListPtr->next, iterationCount++ );
493 	ENSURES( iterationCount < FAILSAFE_ITERATIONS_LARGE );
494 	if( contentListPtr == NULL )
495 		{
496 		/* We didn't get to the encrypted data, the decryption will be set
497 		   up by the de-enveloping code when we reach the data */
498 		return( CRYPT_OK );
499 		}
500 
501 	/* If we're using standard (non-authenticated) encryption, the
502 	   encryption parameters have been provided directly as part of the
503 	   content information so we can set up the decryption and exit */
504 	if( contentListPtr->type != CONTENT_AUTHENC )
505 		{
506 		encrInfo = &contentListPtr->clEncrInfo;
507 		return( initEnvelopeEncryption( envelopeInfoPtr, iSessionKeyContext,
508 								encrInfo->cryptAlgo, encrInfo->cryptMode,
509 								encrInfo->saltOrIV, encrInfo->saltOrIVsize,
510 								FALSE ) );
511 		}
512 
513 	/* We're using authenticated encryption, in which case the "session key"
514 	   that we've been given is actually a generic-secret context from which
515 	   the encryption and MAC contexts and keys have to be derived */
516 	authEncInfo = &contentListPtr->clAuthEncInfo;
517 
518 	/* Recover the KDF information if it's present */
519 	if( authEncInfo->kdfDataLength > 0 )
520 		{
521 		sMemConnect( &stream, authEncInfo->kdfData,
522 					 authEncInfo->kdfDataLength );
523 		readConstructed( &stream, NULL, 0 );
524 		readUniversal( &stream );
525 		status = readShortInteger( &stream, NULL );
526 		if( cryptStatusOK( status ) )
527 			status = readAlgoIDex( &stream, &kdfAlgo, NULL, &kdfAlgoParam,
528 								   ALGOID_CLASS_HASH );
529 		sMemDisconnect( &stream );
530 		if( cryptStatusError( status ) )
531 			return( status );
532 		}
533 	else
534 		{
535 		/* The PBKDF2 default KDF is HMAC-SHA1 */
536 		kdfAlgo = CRYPT_ALGO_HMAC_SHA1;
537 		kdfAlgoParam = 0;
538 		}
539 
540 	/* Recreate the encryption and MAC contexts used for the authenticated
541 	   encryption from the algorithm parameter data stored with the generic-
542 	   secret context */
543 	sMemConnect( &stream, authEncInfo->encParamData,
544 				 authEncInfo->encParamDataLength );
545 	status = readContextAlgoID( &stream, &iAuthEncCryptContext, NULL,
546 								DEFAULT_TAG, ALGOID_CLASS_CRYPT );
547 	sMemDisconnect( &stream );
548 	if( cryptStatusError( status ) )
549 		return( status );
550 	sMemConnect( &stream, authEncInfo->macParamData,
551 				 authEncInfo->macParamDataLength );
552 	status = readContextAlgoID( &stream, &iAuthEncMacContext, NULL,
553 								DEFAULT_TAG, ALGOID_CLASS_HASH );
554 	sMemDisconnect( &stream );
555 	if( cryptStatusError( status ) )
556 		{
557 		krnlSendNotifier( iAuthEncCryptContext, IMESSAGE_DECREFCOUNT );
558 		return( status );
559 		}
560 
561 	/* Set up the encryption parameters using the parameter data recovered
562 	   from the generic-secret context */
563 	memset( &localEncrInfo, 0, sizeof( CONTENT_ENCR_INFO ) );
564 	status = krnlSendMessage( iAuthEncCryptContext, IMESSAGE_GETATTRIBUTE,
565 							  &value, CRYPT_CTXINFO_ALGO );
566 	if( cryptStatusOK( status ) )
567 		{
568 		localEncrInfo.cryptAlgo = value;	/* int vs.enum */
569 		status = krnlSendMessage( iAuthEncCryptContext, IMESSAGE_GETATTRIBUTE,
570 								  &value, CRYPT_CTXINFO_MODE );
571 		}
572 	if( cryptStatusOK( status ) )
573 		{
574 		MESSAGE_DATA msgData;
575 
576 		localEncrInfo.cryptMode = value;	/* int vs.enum */
577 		setMessageData( &msgData, localEncrInfo.saltOrIV,
578 						CRYPT_MAX_HASHSIZE );
579 		status = krnlSendMessage( iAuthEncCryptContext, IMESSAGE_GETATTRIBUTE_S,
580 								  &msgData, CRYPT_CTXINFO_IV );
581 		if( cryptStatusOK( status ) )
582 			localEncrInfo.saltOrIVsize = msgData.length;
583 		}
584 	if( cryptStatusError( status ) )
585 		{
586 		krnlSendNotifier( iAuthEncCryptContext, IMESSAGE_DECREFCOUNT );
587 		krnlSendNotifier( iAuthEncMacContext, IMESSAGE_DECREFCOUNT );
588 		return( status );
589 		}
590 	encrInfo = &localEncrInfo;
591 
592 	/* Derive the encryption and MAC keys from the generic-secret key */
593 	setMechanismKDFInfo( &mechanismInfo, iAuthEncCryptContext,
594 						 iSessionKeyContext, kdfAlgo, "encryption", 10 );
595 	status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_DEV_KDF,
596 							  &mechanismInfo, MECHANISM_DERIVE_PKCS5 );
597 	if( cryptStatusOK( status ) )
598 		{
599 		setMechanismKDFInfo( &mechanismInfo, iAuthEncMacContext,
600 							 iSessionKeyContext, kdfAlgo, "authentication", 14 );
601 		status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_DEV_KDF,
602 								  &mechanismInfo, MECHANISM_DERIVE_PKCS5 );
603 		}
604 	if( cryptStatusError( status ) )
605 		{
606 		krnlSendNotifier( iAuthEncCryptContext, IMESSAGE_DECREFCOUNT );
607 		krnlSendNotifier( iAuthEncMacContext, IMESSAGE_DECREFCOUNT );
608 		return( status );
609 		}
610 
611 	/* We've got the encryption context and information ready, set up the
612 	   decryption */
613 	status = initEnvelopeEncryption( envelopeInfoPtr,
614 							iAuthEncCryptContext, encrInfo->cryptAlgo,
615 							encrInfo->cryptMode, encrInfo->saltOrIV,
616 							encrInfo->saltOrIVsize, FALSE );
617 	if( cryptStatusError( status ) )
618 		{
619 		krnlSendNotifier( iAuthEncCryptContext, IMESSAGE_DECREFCOUNT );
620 		krnlSendNotifier( iAuthEncMacContext, IMESSAGE_DECREFCOUNT );
621 		return( status );
622 		}
623 
624 	/* MAC the EncryptedContentInfo.ContentEncryptionAlgorithmIdentifier
625 	   information alongside the payload data to prevent an attacker from
626 	   manipulating the algorithm parameters to cause corruption that won't
627 	   be detected by the MAC on the payload data */
628 	status = krnlSendMessage( iAuthEncMacContext, IMESSAGE_CTX_HASH,
629 							  ( MESSAGE_CAST ) authEncInfo->authEncParamData,
630 							  authEncInfo->authEncParamLength );
631 	if( cryptStatusError( status ) )
632 		{
633 		krnlSendNotifier( iAuthEncCryptContext, IMESSAGE_DECREFCOUNT );
634 		krnlSendNotifier( iAuthEncMacContext, IMESSAGE_DECREFCOUNT );
635 		return( status );
636 		}
637 
638 	*iCryptContext = iAuthEncCryptContext;
639 	*iMacContext = iAuthEncMacContext;
640 
641 	/* We're now MACing the data via a level of indirection (in other words
642 	   we haven't gone directly via a MACAlgorithmIdentifier in the envelope
643 	   header) so we need to explicitly turn on hashing */
644 	envelopeInfoPtr->dataFlags |= ENVDATA_AUTHENCACTIONSACTIVE;
645 
646 	/* Let the caller know that the contexts have been switched */
647 	return( OK_SPECIAL );
648 	}
649 
650 /* Set up the envelope decryption using an added or recovered session key */
651 
652 CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
initSessionKeyDecryption(INOUT ENVELOPE_INFO * envelopeInfoPtr,IN_HANDLE const CRYPT_CONTEXT iSessionKeyContext,const BOOLEAN isRecoveredSessionKey)653 static int initSessionKeyDecryption( INOUT ENVELOPE_INFO *envelopeInfoPtr,
654 									 IN_HANDLE \
655 										const CRYPT_CONTEXT iSessionKeyContext,
656 									 const BOOLEAN isRecoveredSessionKey )
657 	{
658 	CRYPT_CONTEXT iCryptContext = iSessionKeyContext;
659 	CRYPT_CONTEXT iMacContext = CRYPT_ERROR;
660 	BOOLEAN isAuthEnc = FALSE;
661 	int status;
662 
663 	assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
664 
665 	REQUIRES( isHandleRangeValid( iSessionKeyContext ) );
666 
667 	/* If we recovered the session key from a key exchange action rather
668 	   than having it passed directly to us by the user, try and set up the
669 	   decryption */
670 	if( isRecoveredSessionKey )
671 		{
672 		status = initKeys( envelopeInfoPtr, iSessionKeyContext,
673 						   &iCryptContext, &iMacContext );
674 		if( cryptStatusError( status ) )
675 			{
676 			if( status != OK_SPECIAL )
677 				return( status );
678 
679 			/* A return status of OK_SPECIAL means that the context has
680 			   changed from a single 'session-key' context containing a
681 			   generic secret to two new contexts, one for encryption and
682 			   the other for authentication */
683 			isAuthEnc = TRUE;
684 			}
685 		}
686 
687 	/* Add the recovered session encryption action to the action list */
688 	status = addActionToList( envelopeInfoPtr, iCryptContext, ACTION_CRYPT );
689 	if( cryptStatusOK( status ) && isAuthEnc )
690 		status = addActionToList( envelopeInfoPtr, iMacContext, ACTION_MAC );
691 	if( cryptStatusError( status ) )
692 		{
693 		if( isAuthEnc )
694 			{
695 			krnlSendNotifier( iCryptContext, IMESSAGE_DECREFCOUNT );
696 			krnlSendNotifier( iMacContext, IMESSAGE_DECREFCOUNT );
697 			}
698 		return( status );
699 		}
700 
701 	/* If we're using authenticated encryption (via CMS's encrypt-then-MAC
702 	   rather than PGP's encrypted soft-of-keyed hash) then the generic-
703 	   secret context that was recovered as the 'session-key' has been
704 	   turned into two new contexts, one for encryption and the other for
705 	   authentication, and we can destroy it */
706 	if( envelopeInfoPtr->usage == ACTION_CRYPT && \
707 		( envelopeInfoPtr->flags & ENVELOPE_AUTHENC ) && \
708 		envelopeInfoPtr->type != CRYPT_FORMAT_PGP )
709 		{
710 		REQUIRES( iSessionKeyContext != iCryptContext );
711 
712 		krnlSendNotifier( iSessionKeyContext, IMESSAGE_DECREFCOUNT );
713 		}
714 
715 	/* Notify the kernel that the encryption/MAC context is attached to the
716 	   envelope.  This is an internal object used only by the envelope so we
717 	   tell the kernel not to increment its reference count when it attaches
718 	   it */
719 	return( krnlSendMessage( envelopeInfoPtr->objectHandle,
720 							 IMESSAGE_SETDEPENDENT,
721 							 ( MESSAGE_CAST ) &iCryptContext,
722 							 SETDEP_OPTION_NOINCREF ) );
723 	}
724 
725 /* Import a wrapped session key (optionally a generic-secret key if we're
726    going via an intermediate step for authenticated encryption) */
727 
728 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3, 4 ) ) \
importSessionKey(const CONTENT_LIST * contentListPtr,IN_HANDLE const CRYPT_CONTEXT iImportContext,OUT_HANDLE_OPT CRYPT_CONTEXT * iSessionKeyContext,INOUT ERROR_INFO * errorInfo)729 static int importSessionKey( const CONTENT_LIST *contentListPtr,
730 							 IN_HANDLE const CRYPT_CONTEXT iImportContext,
731 							 OUT_HANDLE_OPT CRYPT_CONTEXT *iSessionKeyContext,
732 							 INOUT ERROR_INFO *errorInfo )
733 	{
734 	CRYPT_CONTEXT iSessionKey;
735 	const CONTENT_LIST *sessionKeyInfoPtr;
736 	MESSAGE_CREATEOBJECT_INFO createInfo;
737 	int iterationCount, status;
738 
739 	assert( isReadPtr( contentListPtr, sizeof( CONTENT_LIST ) ) );
740 	assert( isWritePtr( iSessionKeyContext, sizeof( CRYPT_CONTEXT ) ) );
741 	assert( isWritePtr( errorInfo, sizeof( ERROR_INFO ) ) );
742 
743 	REQUIRES( isHandleRangeValid( iImportContext ) );
744 
745 	/* Clear return value */
746 	*iSessionKeyContext = CRYPT_ERROR;
747 
748 #ifdef USE_PGP
749 	/* PGP doesn't provide separate session key information with the
750 	   encrypted data but wraps it up alongside the encrypted key so we
751 	   can't import the wrapped key into a context via the standard key
752 	   import functions but instead have to create the context as part of
753 	   the unwrap process */
754 	if( contentListPtr->formatType == CRYPT_FORMAT_PGP )
755 		{
756 		return( iCryptImportKey( contentListPtr->object,
757 								 contentListPtr->objectSize,
758 								 CRYPT_FORMAT_PGP, iImportContext,
759 								 CRYPT_UNUSED, iSessionKeyContext ) );
760 		}
761 #endif /* USE_PGP */
762 
763 	/* Look for the information required to recreate the session key (or
764 	   generic-secret) context */
765 	for( sessionKeyInfoPtr = contentListPtr, iterationCount = 0;
766 		 sessionKeyInfoPtr != NULL && \
767 			sessionKeyInfoPtr->envInfo != CRYPT_ENVINFO_SESSIONKEY && \
768 			iterationCount < FAILSAFE_ITERATIONS_LARGE;
769 		 sessionKeyInfoPtr = sessionKeyInfoPtr->next, iterationCount++ );
770 	ENSURES( iterationCount < FAILSAFE_ITERATIONS_LARGE );
771 	if( sessionKeyInfoPtr == NULL )
772 		{
773 		/* We need to read more data before we can recreate the session key */
774 		return( CRYPT_ERROR_UNDERFLOW );
775 		}
776 
777 	/* Create the session/generic-secret key context */
778 	if( sessionKeyInfoPtr->type == CONTENT_CRYPT )
779 		{
780 		const CONTENT_ENCR_INFO *encrInfo = &sessionKeyInfoPtr->clEncrInfo;
781 		int mode;
782 
783 		/* It's conventional encrypted data, import the session key and
784 		   set the encryption mode */
785 		setMessageCreateObjectInfo( &createInfo, encrInfo->cryptAlgo );
786 		status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
787 								  IMESSAGE_DEV_CREATEOBJECT, &createInfo,
788 								  OBJECT_TYPE_CONTEXT );
789 		if( cryptStatusError( status ) )
790 			{
791 			retExt( status,
792 					( status, errorInfo,
793 					  "Couldn't create decryption context for algorithm %d",
794 					  encrInfo->cryptAlgo ) );
795 			}
796 		mode = encrInfo->cryptMode;	/* int vs.enum */
797 		status = krnlSendMessage( createInfo.cryptHandle,
798 								  IMESSAGE_SETATTRIBUTE, &mode,
799 								  CRYPT_CTXINFO_MODE );
800 		if( cryptStatusError( status ) )
801 			{
802 			krnlSendNotifier( createInfo.cryptHandle, IMESSAGE_DECREFCOUNT );
803 			return( status );
804 			}
805 		}
806 	else
807 		{
808 		const CONTENT_AUTHENC_INFO *authEncInfo = \
809 							&sessionKeyInfoPtr->clAuthEncInfo;
810 
811 		/* It's authenticated-encrypted data, import the generic-secret
812 		   context used to create the encryption and MAC contexts */
813 		setMessageCreateObjectInfo( &createInfo, authEncInfo->authEncAlgo );
814 		status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
815 								  IMESSAGE_DEV_CREATEOBJECT, &createInfo,
816 								  OBJECT_TYPE_CONTEXT );
817 		if( cryptStatusError( status ) )
818 			{
819 			retExt( status,
820 					( status, errorInfo,
821 					  "Couldn't create decryption context for algorithm %d",
822 					  authEncInfo->authEncAlgo ) );
823 			}
824 		}
825 	iSessionKey = createInfo.cryptHandle;
826 
827 	/* Import the wrapped session/generic-secret key */
828 	status = iCryptImportKey( contentListPtr->object,
829 							  contentListPtr->objectSize,
830 							  contentListPtr->formatType, iImportContext,
831 							  iSessionKey, NULL );
832 	if( cryptStatusError( status ) )
833 		{
834 		krnlSendNotifier( iSessionKey, IMESSAGE_DECREFCOUNT );
835 		return( status );
836 		}
837 	*iSessionKeyContext = iSessionKey;
838 
839 	return( CRYPT_OK );
840 	}
841 
842 /****************************************************************************
843 *																			*
844 *							Add De-enveloping Information 					*
845 *																			*
846 ****************************************************************************/
847 
848 /* Add signature verification information.  Note that the hashAlgo parameter
849    is an int instead of the more obvious CRYPT_ALGO_TYPE because this
850    function is a function parameter of type CHECKACTIONFUNCTION for which
851    the second argument is a generic integer parameter */
852 
853 CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
findHashActionFunction(const ACTION_LIST * actionListPtr,const int hashAlgo)854 static int findHashActionFunction( const ACTION_LIST *actionListPtr,
855 								   const int hashAlgo )
856 	{
857 	int actionCryptAlgo, status;
858 
859 	assert( isReadPtr( actionListPtr, sizeof( ACTION_LIST ) ) );
860 
861 	REQUIRES( isHashAlgo( hashAlgo ) );
862 
863 	/* Check to see if it's the action that we want */
864 	status = krnlSendMessage( actionListPtr->iCryptHandle,
865 							  IMESSAGE_GETATTRIBUTE, &actionCryptAlgo,
866 							  CRYPT_CTXINFO_ALGO );
867 	if( cryptStatusError( status ) )
868 		return( CRYPT_ERROR );
869 	return( ( actionCryptAlgo == hashAlgo ) ? CRYPT_OK : CRYPT_ERROR );
870 	}
871 
872 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
addSignatureInfo(INOUT ENVELOPE_INFO * envelopeInfoPtr,INOUT CONTENT_LIST * contentListPtr,IN_HANDLE const CRYPT_HANDLE sigCheckContext,const BOOLEAN isExternalKey)873 static int addSignatureInfo( INOUT ENVELOPE_INFO *envelopeInfoPtr,
874 							 INOUT CONTENT_LIST *contentListPtr,
875 							 IN_HANDLE const CRYPT_HANDLE sigCheckContext,
876 							 const BOOLEAN isExternalKey )
877 	{
878 	CONTENT_SIG_INFO *sigInfo = &contentListPtr->clSigInfo;
879 	ACTION_LIST *actionListPtr;
880 	int status;
881 
882 	assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
883 	assert( isWritePtr( contentListPtr, sizeof( CONTENT_LIST ) ) );
884 
885 	REQUIRES( isHandleRangeValid( sigCheckContext ) );
886 
887 	/* If we've already processed this entry, return the cached processing
888 	   result */
889 	if( contentListPtr->flags & CONTENTLIST_PROCESSED )
890 		return( sigInfo->processingResult );
891 
892 	/* Find the hash action that we need to check this signature.  If we
893 	   can't find one, return a bad signature error since something must
894 	   have altered the algorithm ID for the hash */
895 	actionListPtr = findActionIndirect( envelopeInfoPtr->actionList,
896 										findHashActionFunction,
897 										sigInfo->hashAlgo );
898 	if( actionListPtr == NULL || actionListPtr->action != ACTION_HASH )
899 		{
900 		contentListPtr->flags |= CONTENTLIST_PROCESSED;
901 		sigInfo->processingResult = CRYPT_ERROR_SIGNATURE;
902 		retExt( CRYPT_ERROR_SIGNATURE,
903 				( CRYPT_ERROR_SIGNATURE, ENVELOPE_ERRINFO,
904 				  "Signature hash algorithm doesn't match hash algorithm "
905 				  "applied to enveloped data" ) );
906 		}
907 
908 	/* Check the signature.  In theory there's an additional check that we
909 	   need to apply at this point that defends against a (hypothesised)
910 	   attack in which, if there are multiple signatures present and they
911 	   use different-strength hash algorithms and an attacker manages to
912 	   break one of them, the attacker can strip the stronger-algorithm
913 	   signature(s) and leave only the weaker-algorithm one(s), allowing
914 	   them to modify the signed data.  The way to handle this is to include
915 	   a reference to every other signature in the current signature.
916 	   However there are (currently) no known implementations of this, which
917 	   makes testing somewhat difficult.  In addition the handling gets very
918 	   tricky, for example if the recipient supports only the weak algorithm
919 	   should they reject the message or accept it?  (The RFC that covers
920 	   this, RFC 5750, says that no matter what occurs in terms of absent or
921 	   present strong or weak-algorithm signatures, the recipient MAY
922 	   consider them valid).  Until both implementations, and more
923 	   importantly users who can specify how they want this handled, appear,
924 	   we leave it for future implementation */
925 	if( contentListPtr->formatType == CRYPT_FORMAT_CMS )
926 		{
927 		status = checkCmsSignatureInfo( contentListPtr,
928 										actionListPtr->iCryptHandle,
929 										sigCheckContext,
930 										envelopeInfoPtr->contentType,
931 										ENVELOPE_ERRINFO );
932 		}
933 	else
934 		{
935 		status = iCryptCheckSignature( contentListPtr->object,
936 								contentListPtr->objectSize,
937 								contentListPtr->formatType, sigCheckContext,
938 								actionListPtr->iCryptHandle, CRYPT_UNUSED,
939 								NULL );
940 		if( cryptStatusError( status ) )
941 			{
942 			/* We need to do this explicitly here since it's not set by
943 			   iCryptCheckSignature() as it is for checkCmsSignatureInfo() */
944 			setErrorString( ENVELOPE_ERRINFO,
945 							"Signature verification failed", 29 );
946 			}
947 
948 		/* If it's a format that includes signing key information remember
949 		   the key that was used to check the signature in case the user
950 		   wants to query it later */
951 		if( contentListPtr->formatType != CRYPT_FORMAT_PGP )
952 			{
953 			krnlSendNotifier( sigCheckContext, IMESSAGE_INCREFCOUNT );
954 			sigInfo->iSigCheckKey = sigCheckContext;
955 			if( isExternalKey )
956 				contentListPtr->flags |= CONTENTLIST_EXTERNALKEY;
957 			}
958 		}
959 
960 	/* Remember the processing result so that we don't have to repeat the
961 	   processing if queried again.  Since we don't need the encoded
962 	   signature data any more after this point we can free it.
963 
964 	   There are a few special-case situations in which a failure at this
965 	   point isn't necessarily fatal, but it's hard to predict in advance
966 	   exactly what all of these could be.  The one obvious one is with a
967 	   CRYPT_ERROR_WRONGKEY, which means that the caller can simply retry
968 	   with a different key, so we make this error non-persistent */
969 	if( status == CRYPT_ERROR_WRONGKEY )
970 		{
971 		setErrorString( ENVELOPE_ERRINFO,
972 						"Incorrect key used to verify signature", 38 );
973 		return( status );
974 		}
975 	clFree( "addSignatureInfo", ( void * ) contentListPtr->object );
976 	contentListPtr->object = NULL;
977 	contentListPtr->objectSize = 0;
978 	contentListPtr->flags |= CONTENTLIST_PROCESSED;
979 	sigInfo->processingResult = cryptArgError( status ) ? \
980 								CRYPT_ERROR_SIGNATURE : status;
981 	return( status );
982 	}
983 
984 /* Add a password for decryption of a private key */
985 
986 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 3 ) ) \
addPrivkeyPasswordInfo(INOUT ENVELOPE_INFO * envelopeInfoPtr,const CONTENT_LIST * contentListPtr,IN_BUFFER (passwordLength)const void * password,IN_LENGTH_TEXT const int passwordLength)987 static int addPrivkeyPasswordInfo( INOUT ENVELOPE_INFO *envelopeInfoPtr,
988 								   const CONTENT_LIST *contentListPtr,
989 								   IN_BUFFER( passwordLength ) const void *password,
990 								   IN_LENGTH_TEXT const int passwordLength )
991 	{
992 	const ENV_ADDINFO_FUNCTION addInfoFunction = \
993 				FNPTR_GET( envelopeInfoPtr->addInfoFunction );
994 	MESSAGE_KEYMGMT_INFO getkeyInfo;
995 	int type, status;
996 
997 	assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
998 	assert( isReadPtr( contentListPtr, sizeof( CONTENT_LIST ) ) );
999 	assert( isReadPtr( password, passwordLength ) );
1000 
1001 	REQUIRES( passwordLength > 0 && passwordLength <= CRYPT_MAX_TEXTSIZE );
1002 	REQUIRES( addInfoFunction != NULL );
1003 
1004 	/* Make sure that there's a keyset available to pull the key from */
1005 	if( envelopeInfoPtr->iDecryptionKeyset == CRYPT_ERROR )
1006 		{
1007 		setErrorInfo( envelopeInfoPtr, CRYPT_ENVINFO_KEYSET_DECRYPT,
1008 					  CRYPT_ERRTYPE_ATTR_ABSENT );
1009 		return( CRYPT_ERROR_NOTINITED );
1010 		}
1011 
1012 	/* Make sure that we're trying to send the password to something for
1013 	   which it makes sense.  Private-key sources aren't just keysets but
1014 	   can also be devices, but if we're trying to send a password to a
1015 	   device to get a private key then something's gone wrong since it
1016 	   should be retrieved automatically from the device, which was unlocked
1017 	   via a PIN or password when a session with it was established */
1018 	status = krnlSendMessage( envelopeInfoPtr->iDecryptionKeyset,
1019 							  IMESSAGE_GETATTRIBUTE, &type,
1020 							  CRYPT_IATTRIBUTE_TYPE );
1021 	if( cryptStatusError( status ) || type != OBJECT_TYPE_KEYSET )
1022 		{
1023 		/* This one is very difficult to report appropriately, the best that
1024 		   we can do is report the wrong key for this type of object */
1025 		setErrorInfo( envelopeInfoPtr, CRYPT_ENVINFO_KEYSET_DECRYPT,
1026 					  CRYPT_ERRTYPE_ATTR_VALUE );
1027 		return( CRYPT_ERROR_WRONGKEY );
1028 		}
1029 
1030 	/* Try and get the key information */
1031 	if( contentListPtr->issuerAndSerialNumber == NULL )
1032 		{
1033 		setMessageKeymgmtInfo( &getkeyInfo,
1034 				( contentListPtr->formatType == CRYPT_FORMAT_PGP ) ? \
1035 				CRYPT_IKEYID_PGPKEYID : CRYPT_IKEYID_KEYID,
1036 				contentListPtr->keyID, contentListPtr->keyIDsize,
1037 				( MESSAGE_CAST ) password, passwordLength,
1038 				KEYMGMT_FLAG_USAGE_CRYPT );
1039 		}
1040 	else
1041 		{
1042 		setMessageKeymgmtInfo( &getkeyInfo,
1043 				CRYPT_IKEYID_ISSUERANDSERIALNUMBER,
1044 				contentListPtr->issuerAndSerialNumber,
1045 				contentListPtr->issuerAndSerialNumberSize,
1046 				( MESSAGE_CAST ) password, passwordLength,
1047 				KEYMGMT_FLAG_USAGE_CRYPT );
1048 		}
1049 	status = krnlSendMessage( envelopeInfoPtr->iDecryptionKeyset,
1050 							  IMESSAGE_KEY_GETKEY, &getkeyInfo,
1051 							  KEYMGMT_ITEM_PRIVATEKEY );
1052 	if( cryptStatusError( status ) )
1053 		{
1054 		retExtObj( status,
1055 				   ( status, ENVELOPE_ERRINFO,
1056 				     envelopeInfoPtr->iDecryptionKeyset,
1057 					 "Couldn't retrieve private key from decryption "
1058 					 "keyset/device" ) );
1059 		}
1060 
1061 	/* We managed to get the private key, push it into the envelope.  If the
1062 	   call succeeds this will import the session key and delete the
1063 	   required-information list, after which we don't need the private key
1064 	   any more */
1065 	status = addInfoFunction( envelopeInfoPtr, CRYPT_ENVINFO_PRIVATEKEY,
1066 							  getkeyInfo.cryptHandle );
1067 	krnlSendNotifier( getkeyInfo.cryptHandle, IMESSAGE_DECREFCOUNT );
1068 	return( status );
1069 	}
1070 
1071 /* Add a decryption password */
1072 
1073 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2, 7 ) ) \
1074 static int addPasswordInfo( const CONTENT_LIST *contentListPtr,
1075 							IN_BUFFER( passwordLength ) const void *password,
1076 							IN_RANGE( 1, CRYPT_MAX_TEXTSIZE ) \
1077 								const int passwordLength,
1078 							IN_HANDLE_OPT const CRYPT_CONTEXT iMacContext,
1079 							OUT_OPT_HANDLE_OPT CRYPT_CONTEXT *iNewContext,
1080 							IN_ENUM( CRYPT_FORMAT ) \
1081 								const CRYPT_FORMAT_TYPE formatType,
1082 							INOUT ERROR_INFO *errorInfo )
1083 	{
1084 	CRYPT_CONTEXT iCryptContext;
1085 	const CONTENT_ENCR_INFO *encrInfo = &contentListPtr->clEncrInfo;
1086 	MESSAGE_CREATEOBJECT_INFO createInfo;
1087 	int mode, status;
1088 
1089 	assert( isReadPtr( contentListPtr, sizeof( CONTENT_LIST ) ) );
1090 	assert( isReadPtr( password, passwordLength ) );
1091 	assert( ( isHandleRangeValid( iMacContext ) && iNewContext == NULL ) || \
1092 			( iMacContext == CRYPT_UNUSED && \
1093 			  isWritePtr( iNewContext, sizeof( CRYPT_CONTEXT ) ) ) );
1094 	assert( isWritePtr( errorInfo, sizeof( ENVELOPE_INFO ) ) );
1095 
1096 	REQUIRES( ( isHandleRangeValid( iMacContext ) && iNewContext == NULL ) || \
1097 			  ( iMacContext == CRYPT_UNUSED && iNewContext != NULL ) );
1098 	REQUIRES( formatType > CRYPT_FORMAT_NONE && \
1099 			  formatType < CRYPT_FORMAT_LAST );
1100 	REQUIRES( formatType != CRYPT_FORMAT_PGP || iNewContext != NULL );
1101 			  /* PGP can't perform MACing, only encryption */
1102 
1103 	/* Clear return value */
1104 	if( iNewContext != NULL )
1105 		*iNewContext = CRYPT_ERROR;
1106 
1107 	/* Create the appropriate encryption context and derive the key into it */
1108 	setMessageCreateObjectInfo( &createInfo, encrInfo->cryptAlgo );
1109 	status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_DEV_CREATEOBJECT,
1110 							  &createInfo, OBJECT_TYPE_CONTEXT );
1111 	if( cryptStatusError( status ) )
1112 		return( status );
1113 	iCryptContext = createInfo.cryptHandle;
1114 	mode = encrInfo->cryptMode;	/* int vs.enum */
1115 	status = krnlSendMessage( iCryptContext, IMESSAGE_SETATTRIBUTE, &mode,
1116 							  CRYPT_CTXINFO_MODE );
1117 	if( cryptStatusOK( status ) )
1118 		{
1119 #ifdef USE_PGP
1120 		if( formatType == CRYPT_FORMAT_PGP )
1121 			{
1122 			status = pgpPasswordToKey( iCryptContext, CRYPT_UNUSED,
1123 							password, passwordLength, encrInfo->keySetupAlgo,
1124 							( encrInfo->saltOrIVsize > 0 ) ? \
1125 								encrInfo->saltOrIV : NULL, encrInfo->saltOrIVsize,
1126 							encrInfo->keySetupIterations );
1127 			}
1128 		else
1129 #endif /* USE_PGP */
1130 			{
1131 			MESSAGE_DATA msgData;
1132 
1133 			/* Load the derivation information into the context */
1134 			if( encrInfo->keySetupAlgo != CRYPT_ALGO_NONE )
1135 				{
1136 				const int algorithm = encrInfo->keySetupAlgo;	/* int vs.enum */
1137 				status = krnlSendMessage( iCryptContext, IMESSAGE_SETATTRIBUTE,
1138 										  ( MESSAGE_CAST ) &algorithm,
1139 										  CRYPT_CTXINFO_KEYING_ALGO );
1140 				}
1141 			if( cryptStatusOK( status ) )
1142 				status = krnlSendMessage( iCryptContext, IMESSAGE_SETATTRIBUTE,
1143 										  ( MESSAGE_CAST ) &encrInfo->keySetupIterations,
1144 										  CRYPT_CTXINFO_KEYING_ITERATIONS );
1145 			if( cryptStatusOK( status ) && encrInfo->keySize > 0 )
1146 				status = krnlSendMessage( iCryptContext, IMESSAGE_SETATTRIBUTE,
1147 										  ( MESSAGE_CAST ) &encrInfo->keySize,
1148 										  CRYPT_CTXINFO_KEYSIZE );
1149 			if( cryptStatusOK( status ) )
1150 				{
1151 				setMessageData( &msgData, ( MESSAGE_CAST ) encrInfo->saltOrIV,
1152 								encrInfo->saltOrIVsize );
1153 				status = krnlSendMessage( iCryptContext,
1154 									IMESSAGE_SETATTRIBUTE_S, &msgData,
1155 									CRYPT_CTXINFO_KEYING_SALT );
1156 				}
1157 			if( cryptStatusOK( status ) )
1158 				{
1159 				setMessageData( &msgData, ( MESSAGE_CAST ) password,
1160 								passwordLength );
1161 				status = krnlSendMessage( iCryptContext,
1162 									IMESSAGE_SETATTRIBUTE_S, &msgData,
1163 									CRYPT_CTXINFO_KEYING_VALUE );
1164 				}
1165 			}
1166 		}
1167 	if( cryptStatusError( status ) )
1168 		{
1169 		krnlSendNotifier( iCryptContext, IMESSAGE_DECREFCOUNT );
1170 		retExt( status,
1171 				( status, errorInfo,
1172 				  "Couldn't derive key-import key from password" ) );
1173 		}
1174 
1175 	/* In PGP there isn't any encrypted session key so the context created
1176 	   from the password becomes the bulk encryption context and we're done */
1177 	if( formatType == CRYPT_FORMAT_PGP )
1178 		{
1179 		*iNewContext = iCryptContext;
1180 
1181 		return( CRYPT_OK );
1182 		}
1183 
1184 	/* Recover the session key using the password context and destroy it
1185 	   when we're done with it */
1186 	if( iNewContext == NULL )
1187 		{
1188 		/* The target is a MAC context (which has already been set up), load
1189 		   the session key directly into it */
1190 		status = iCryptImportKey( contentListPtr->object,
1191 								  contentListPtr->objectSize,
1192 								  contentListPtr->formatType,
1193 								  iCryptContext, iMacContext, NULL );
1194 		}
1195 	else
1196 		{
1197 		/* The target is an encryption context, recreate it from the
1198 		   encrypted session key information */
1199 		status = importSessionKey( contentListPtr, iCryptContext,
1200 								   iNewContext, errorInfo );
1201 		}
1202 	krnlSendNotifier( iCryptContext, IMESSAGE_DECREFCOUNT );
1203 	if( cryptStatusError( status ) )
1204 		{
1205 		retExt( status,
1206 				( status, errorInfo,
1207 				  "Couldn't recover wrapped session key" ) );
1208 		}
1209 
1210 	return( CRYPT_OK );
1211 	}
1212 
1213 /****************************************************************************
1214 *																			*
1215 *					De-enveloping Information Management Functions			*
1216 *																			*
1217 ****************************************************************************/
1218 
1219 /* Try and match what's being added to an information object in the content
1220    list */
1221 
1222 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
matchInfoObject(OUT_PTR_OPT CONTENT_LIST ** contentListPtrPtr,const ENVELOPE_INFO * envelopeInfoPtr,IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE envInfo)1223 static int matchInfoObject( OUT_PTR_OPT CONTENT_LIST **contentListPtrPtr,
1224 							const ENVELOPE_INFO *envelopeInfoPtr,
1225 							IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE envInfo )
1226 	{
1227 	CONTENT_LIST *contentListPtr = envelopeInfoPtr->contentListCurrent;
1228 	const BOOLEAN privateKeyFetch = \
1229 		( envInfo == CRYPT_ENVINFO_PASSWORD && \
1230 		  envelopeInfoPtr->iDecryptionKeyset != CRYPT_ERROR ) ? TRUE : FALSE;
1231 	int iterationCount;
1232 
1233 	assert( isWritePtr( contentListPtrPtr, sizeof( CONTENT_LIST * ) ) );
1234 	assert( isReadPtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
1235 
1236 	REQUIRES( envInfo == CRYPT_IATTRIBUTE_ATTRONLY || \
1237 			  ( envInfo > CRYPT_ENVINFO_FIRST && \
1238 				envInfo < CRYPT_ENVINFO_LAST ) );
1239 
1240 	/* Clear return value */
1241 	*contentListPtrPtr = NULL;
1242 
1243 	/* If we're adding meta-information there's nothing to check */
1244 	if( envInfo == CRYPT_IATTRIBUTE_ATTRONLY || \
1245 		envInfo == CRYPT_ENVINFO_DETACHEDSIGNATURE || \
1246 		envInfo == CRYPT_ENVINFO_KEYSET_SIGCHECK || \
1247 		envInfo == CRYPT_ENVINFO_KEYSET_ENCRYPT || \
1248 		envInfo == CRYPT_ENVINFO_KEYSET_DECRYPT || \
1249 		envInfo == CRYPT_ENVINFO_HASH )
1250 		return( CRYPT_OK );
1251 
1252 	/* If there's already a content-list item selected, make sure that the
1253 	   information that we're adding matches the current information object.
1254 	   The one exception to this is that we can be passed password
1255 	   information when we require a private key if the private key is
1256 	   encrypted */
1257 	if( contentListPtr != NULL )
1258 		{
1259 		if( contentListPtr->envInfo != envInfo && \
1260 			!( contentListPtr->envInfo == CRYPT_ENVINFO_PRIVATEKEY && \
1261 			   privateKeyFetch ) )
1262 			return( CRYPT_ARGERROR_VALUE );
1263 
1264 		*contentListPtrPtr = contentListPtr;
1265 		return( CRYPT_OK );
1266 		}
1267 
1268 	/* Look for the first information object that matches the supplied
1269 	   information */
1270 	for( contentListPtr = envelopeInfoPtr->contentList, iterationCount = 0;
1271 		 contentListPtr != NULL && contentListPtr->envInfo != envInfo && \
1272 			iterationCount < FAILSAFE_ITERATIONS_LARGE;
1273 		 contentListPtr = contentListPtr->next, iterationCount++ );
1274 	ENSURES( iterationCount < FAILSAFE_ITERATIONS_LARGE );
1275 	if( contentListPtr == NULL && privateKeyFetch )
1276 		{
1277 		/* If we didn't find a direct match and we've been given a password,
1278 		   check for a private key that can (potentially) be decrypted using
1279 		   the password.  This requires both a keyset/device to fetch the
1280 		   key from and a private key as the required info type */
1281 		for( contentListPtr = envelopeInfoPtr->contentList, iterationCount = 0;
1282 			 contentListPtr != NULL && \
1283 				contentListPtr->envInfo != CRYPT_ENVINFO_PRIVATEKEY && \
1284 				iterationCount < FAILSAFE_ITERATIONS_LARGE;
1285 			 contentListPtr = contentListPtr->next, iterationCount++ );
1286 		ENSURES( iterationCount < FAILSAFE_ITERATIONS_LARGE );
1287 		}
1288 	if( contentListPtr == NULL )
1289 		return( CRYPT_ARGERROR_VALUE );
1290 
1291 	*contentListPtrPtr = contentListPtr;
1292 	return( CRYPT_OK );
1293 	}
1294 
1295 /* Complete the addition of information to an envelope */
1296 
1297 CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
completeEnvelopeInfoUpdate(INOUT ENVELOPE_INFO * envelopeInfoPtr)1298 static int completeEnvelopeInfoUpdate( INOUT ENVELOPE_INFO *envelopeInfoPtr )
1299 	{
1300 	assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
1301 
1302 	/* Destroy the content list, which at this point will contain only (now-
1303 	   irrelevant) key exchange items */
1304 	deleteContentList( envelopeInfoPtr->memPoolState,
1305 					   &envelopeInfoPtr->contentList );
1306 	envelopeInfoPtr->contentList = envelopeInfoPtr->contentListCurrent = NULL;
1307 
1308 	/* If the only error was an information required error, we've now
1309 	   resolved the problem and can continue */
1310 	if( envelopeInfoPtr->errorState == CRYPT_ENVELOPE_RESOURCE )
1311 		{
1312 		envelopeInfoPtr->errorState = CRYPT_OK;
1313 
1314 		/* The envelope is ready to process data, move it into the high
1315 		   state.  Normally this is handled in the data-push code but this
1316 		   leads to a race condition when all the data being pushed is
1317 		   buffered inside the envelope, requiring only that processing be
1318 		   enabled by adding a resource.  Once the resource is added the
1319 		   only action left for the caller to perform is a flush, so they
1320 		   expect that high-state actions should succeed even though the
1321 		   envelope state machine wouldn't move the envelope into the high
1322 		   state until some data action (in this case a flush) is
1323 		   initiated.  To avoid this problem we move the envelope into the
1324 		   high state as soon as the resource blockage has been cleared,
1325 		   since any high-state-only information (for example the nested
1326 		   content type) will now be available */
1327 		return( krnlSendMessage( envelopeInfoPtr->objectHandle,
1328 								 IMESSAGE_SETATTRIBUTE, MESSAGE_VALUE_UNUSED,
1329 								 CRYPT_IATTRIBUTE_INITIALISED ) );
1330 		}
1331 
1332 	return( CRYPT_OK );
1333 	}
1334 
1335 /* Add de-enveloping information to an envelope */
1336 
1337 CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
addDeenvelopeInfo(INOUT ENVELOPE_INFO * envelopeInfoPtr,IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE envInfo,IN_INT_Z const int value)1338 static int addDeenvelopeInfo( INOUT ENVELOPE_INFO *envelopeInfoPtr,
1339 							  IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE envInfo,
1340 							  IN_INT_Z const int value )
1341 	{
1342 	CRYPT_HANDLE cryptHandle = ( CRYPT_HANDLE ) value;
1343 	CRYPT_CONTEXT iNewContext DUMMY_INIT;
1344 	CRYPT_ATTRIBUTE_TYPE localEnvInfo = envInfo;
1345 	CONTENT_LIST *contentListPtr;
1346 	BOOLEAN isExternalKey = TRUE;
1347 	int status = CRYPT_OK;
1348 
1349 	assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
1350 
1351 	REQUIRES( envInfo == CRYPT_IATTRIBUTE_ATTRONLY || \
1352 			  ( envInfo > CRYPT_ENVINFO_FIRST && \
1353 				envInfo < CRYPT_ENVINFO_LAST ) );
1354 
1355 	/* A signature-check object can be passed in as a special-case type
1356 	   CRYPT_ENVINFO_SIGNATURE_RESULT to indicate that the object was
1357 	   obtained internally (for example by instantiating it from an attached
1358 	   certificate chain) and doesn't require various special-case
1359 	   operations that are applied to user-supplied objects.  If this is the
1360 	   case we convert it to a standard CRYPT_ENVINFO_SIGNATURE and remember
1361 	   that it's an internally-supplied key */
1362 	if( envInfo == CRYPT_ENVINFO_SIGNATURE_RESULT )
1363 		{
1364 		localEnvInfo = CRYPT_ENVINFO_SIGNATURE;
1365 		isExternalKey = FALSE;
1366 		}
1367 
1368 	/* Since we can add one of a multitude of necessary information types
1369 	   we need to check to make sure that what we're adding is appropriate.
1370 	   We do this by trying to match what's being added to the first
1371 	   information object of the correct type */
1372 	status = matchInfoObject( &contentListPtr, envelopeInfoPtr,
1373 							  localEnvInfo );
1374 	if( cryptStatusError( status ) )
1375 		{
1376 		retExtArg( status,
1377 				   ( status, ENVELOPE_ERRINFO,
1378 					 "Added item doesn't match %s envelope information "
1379 					 "object",
1380 					 ( envelopeInfoPtr->contentListCurrent != NULL ) ? \
1381 						"currently selected" : "any" ) );
1382 		}
1383 
1384 	/* Process non-encryption-related enveloping info */
1385 	switch( localEnvInfo )
1386 		{
1387 		case CRYPT_IATTRIBUTE_ATTRONLY:
1388 			/* This is off by default so we should only be turning it on */
1389 			REQUIRES( value == TRUE );
1390 
1391 			envelopeInfoPtr->flags |= ENVELOPE_ATTRONLY;
1392 			return( CRYPT_OK );
1393 
1394 		case CRYPT_ENVINFO_DETACHEDSIGNATURE:
1395 			envelopeInfoPtr->flags |= ENVELOPE_DETACHED_SIG;
1396 			return( CRYPT_OK );
1397 
1398 		case CRYPT_ENVINFO_KEYSET_SIGCHECK:
1399 		case CRYPT_ENVINFO_KEYSET_ENCRYPT:
1400 		case CRYPT_ENVINFO_KEYSET_DECRYPT:
1401 			/* It's keyset information, keep a record of it for later use */
1402 			return( addKeysetInfo( envelopeInfoPtr, localEnvInfo,
1403 								   cryptHandle ) );
1404 
1405 		case CRYPT_ENVINFO_HASH:
1406 			{
1407 			ACTION_LIST *actionListItem;
1408 
1409 			/* The user is checking a detached signature, remember the hash
1410 			   for later.  In theory we should also check the state of the
1411 			   hash context, however PGP requires that it not be completed
1412 			   (since it needs to hash further data) and everything else
1413 			   requires that it be completed, but we don't know at this
1414 			   point whether we're processing PGP or non-PGP data so we
1415 			   can't perform any checking here */
1416 			if( envelopeInfoPtr->actionList != NULL )
1417 				{
1418 				/* There's already a hash action present, we can't add
1419 				   anything further */
1420 				setErrorInfo( envelopeInfoPtr, CRYPT_ENVINFO_HASH,
1421 							  CRYPT_ERRTYPE_ATTR_PRESENT );
1422 				return( CRYPT_ERROR_INITED );
1423 				}
1424 
1425 			/* Make sure that we can still add another action */
1426 			if( !moreActionsPossible( envelopeInfoPtr->actionList ) )
1427 				return( CRYPT_ERROR_OVERFLOW );
1428 
1429 			/* Add the hash as an action list item */
1430 			status = addActionEx( &actionListItem,
1431 								  &envelopeInfoPtr->actionList,
1432 								  envelopeInfoPtr->memPoolState,
1433 								  ACTION_HASH, cryptHandle );
1434 			if( cryptStatusError( status ) )
1435 				return( status );
1436 			return( krnlSendNotifier( cryptHandle, IMESSAGE_INCREFCOUNT ) );
1437 			}
1438 
1439 		case CRYPT_ENVINFO_SIGNATURE:
1440 			/* It's a signature object, check the signature and exit */
1441 			return( addSignatureInfo( envelopeInfoPtr, contentListPtr,
1442 									  cryptHandle, isExternalKey ) );
1443 		}
1444 
1445 	/* Make sure that we can still add another action */
1446 	if( !moreActionsPossible( envelopeInfoPtr->actionList ) )
1447 		return( CRYPT_ERROR_OVERFLOW );
1448 
1449 	/* Anything that's left at this point related to envelope decryption */
1450 	switch( localEnvInfo )
1451 		{
1452 		case CRYPT_ENVINFO_PRIVATEKEY:
1453 		case CRYPT_ENVINFO_KEY:
1454 			/* Import the session key using the KEK */
1455 			status = importSessionKey( contentListPtr, cryptHandle,
1456 									   &iNewContext, ENVELOPE_ERRINFO );
1457 			break;
1458 
1459 		case CRYPT_ENVINFO_SESSIONKEY:
1460 			{
1461 			/* If we've been given the session key directly then we must
1462 			   have reached the encrypted data so we take a copy and set
1463 			   up the decryption with it */
1464 			const CONTENT_ENCR_INFO *encrInfo = &contentListPtr->clEncrInfo;
1465 
1466 			status = initEnvelopeEncryption( envelopeInfoPtr, cryptHandle,
1467 							encrInfo->cryptAlgo, encrInfo->cryptMode,
1468 							encrInfo->saltOrIV, encrInfo->saltOrIVsize, TRUE );
1469 			if( cryptStatusOK( status ) )
1470 				{
1471 				/* The session key context is the newly-created internal
1472 				   one */
1473 				iNewContext = envelopeInfoPtr->iCryptContext;
1474 				}
1475 			break;
1476 			}
1477 
1478 		default:
1479 			retIntError();
1480 		}
1481 	if( cryptStatusError( status ) )
1482 		return( status );
1483 
1484 	/* We've now got the session key, if we recovered it from a key exchange
1485 	   action (rather than having it passed directly to us by the user) try
1486 	   and set up the decryption */
1487 	if( envelopeInfoPtr->usage != ACTION_MAC )
1488 		{
1489 		status = initSessionKeyDecryption( envelopeInfoPtr, iNewContext,
1490 							( localEnvInfo != CRYPT_ENVINFO_SESSIONKEY ) ? \
1491 								TRUE : FALSE );
1492 		if( cryptStatusError( status ) )
1493 			{
1494 			if( localEnvInfo != CRYPT_ENVINFO_SESSIONKEY )
1495 				krnlSendNotifier( iNewContext, IMESSAGE_DECREFCOUNT );
1496 			if( status == CRYPT_ERROR_INITED )
1497 				{
1498 				/* If the attribute that we added to recover the session key
1499 				   is already present, provide extended error information */
1500 				setErrorInfo( envelopeInfoPtr, localEnvInfo,
1501 							  CRYPT_ERRTYPE_ATTR_PRESENT );
1502 				}
1503 			return( status );
1504 			}
1505 		}
1506 
1507 	/* Complete the envelope information update */
1508 	return( completeEnvelopeInfoUpdate( envelopeInfoPtr ) );
1509 	}
1510 
1511 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3 ) ) \
1512 static int addDeenvelopeInfoString( INOUT ENVELOPE_INFO *envelopeInfoPtr,
1513 									IN_RANGE( CRYPT_ENVINFO_PASSWORD, \
1514 											  CRYPT_ENVINFO_PASSWORD ) \
1515 										const CRYPT_ATTRIBUTE_TYPE envInfo,
1516 									IN_BUFFER( valueLength ) const void *value,
1517 									IN_RANGE( 1, CRYPT_MAX_TEXTSIZE ) \
1518 										const int valueLength )
1519 	{
1520 	CRYPT_CONTEXT iNewContext DUMMY_INIT;
1521 	CONTENT_LIST *contentListPtr;
1522 	int status;
1523 
1524 	assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
1525 	assert( isReadPtr( value, valueLength ) );
1526 
1527 	REQUIRES( envInfo == CRYPT_ENVINFO_PASSWORD );
1528 	REQUIRES( valueLength > 0 && valueLength < MAX_ATTRIBUTE_SIZE );
1529 
1530 	/* Since we can add one of a multitude of necessary information types,
1531 	   we need to check to make sure that what we're adding is appropriate.
1532 	   We do this by trying to match what's being added to the first
1533 	   information object of the correct type */
1534 	status = matchInfoObject( &contentListPtr, envelopeInfoPtr, envInfo );
1535 	if( cryptStatusError( status ) )
1536 		{
1537 		retExtArg( status,
1538 				   ( status, ENVELOPE_ERRINFO,
1539 					 "Added item doesn't match any envelope information "
1540 					 "object" ) );
1541 		}
1542 
1543 	/* If we've been given a password and we need private key information,
1544 	   it's the password required to decrypt the key so we treat this
1545 	   specially.  This action recursively calls addDeenvelopeInfo() with
1546 	   the processed private key so we don't have to fall through to the
1547 	   session-key processing code below like the other key-handling
1548 	   actions */
1549 	if( contentListPtr->envInfo == CRYPT_ENVINFO_PRIVATEKEY )
1550 		{
1551 		return( addPrivkeyPasswordInfo( envelopeInfoPtr, contentListPtr,
1552 										value, valueLength ) );
1553 		}
1554 
1555 	/* Make sure that we can still add another action */
1556 	if( envelopeInfoPtr->usage != ACTION_MAC && \
1557 		!moreActionsPossible( envelopeInfoPtr->actionList ) )
1558 		return( CRYPT_ERROR_OVERFLOW );
1559 
1560 	/* We've been given a standard decryption password, create a decryption
1561 	   context for it, derive the key from the password, and use it to
1562 	   import the session/MAC key */
1563 	if( envelopeInfoPtr->usage == ACTION_MAC )
1564 		{
1565 		if( envelopeInfoPtr->actionList == NULL )
1566 			return( CRYPT_ERROR_NOTINITED );
1567 		status = addPasswordInfo( contentListPtr, value, valueLength,
1568 								  envelopeInfoPtr->actionList->iCryptHandle,
1569 								  NULL, envelopeInfoPtr->type,
1570 								  ENVELOPE_ERRINFO );
1571 		}
1572 	else
1573 		{
1574 		status = addPasswordInfo( contentListPtr, value, valueLength,
1575 								  CRYPT_UNUSED, &iNewContext,
1576 								  envelopeInfoPtr->type, ENVELOPE_ERRINFO );
1577 		}
1578 	if( cryptStatusError( status ) )
1579 		return( status );
1580 
1581 	/* We've recovered the session key, try and set up the decryption */
1582 	if( envelopeInfoPtr->usage != ACTION_MAC )
1583 		{
1584 		status = initSessionKeyDecryption( envelopeInfoPtr, iNewContext,
1585 										   TRUE );
1586 		if( cryptStatusError( status ) )
1587 			{
1588 			krnlSendNotifier( iNewContext, IMESSAGE_DECREFCOUNT );
1589 			if( status == CRYPT_ERROR_INITED )
1590 				{
1591 				/* If the attribute that we added to recover the session key
1592 				   is already present, provide extended error information */
1593 				setErrorInfo( envelopeInfoPtr, envInfo,
1594 							  CRYPT_ERRTYPE_ATTR_PRESENT );
1595 				}
1596 			return( status );
1597 			}
1598 		}
1599 
1600 	/* Complete the envelope information update */
1601 	return( completeEnvelopeInfoUpdate( envelopeInfoPtr ) );
1602 	}
1603 
1604 /****************************************************************************
1605 *																			*
1606 *							Envelope Access Routines						*
1607 *																			*
1608 ****************************************************************************/
1609 
1610 STDC_NONNULL_ARG( ( 1 ) ) \
initDenvResourceHandling(INOUT ENVELOPE_INFO * envelopeInfoPtr)1611 void initDenvResourceHandling( INOUT ENVELOPE_INFO *envelopeInfoPtr )
1612 	{
1613 	assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
1614 
1615 	REQUIRES_V( envelopeInfoPtr->flags & ENVELOPE_ISDEENVELOPE );
1616 
1617 	/* Set the access method pointers */
1618 	FNPTR_SET( envelopeInfoPtr->addInfoFunction, addDeenvelopeInfo );
1619 	FNPTR_SET( envelopeInfoPtr->addInfoStringFunction, addDeenvelopeInfoString );
1620 	}
1621 #endif /* USE_ENVELOPES */
1622