1 /****************************************************************************
2 *																			*
3 *						cryptlib CMS Pre-enveloping Routines				*
4 *					    Copyright Peter Gutmann 1996-2010					*
5 *																			*
6 ****************************************************************************/
7 
8 #if defined( INC_ALL )
9   #include "asn1.h"
10   #include "asn1_ext.h"
11   #include "envelope.h"
12 #else
13   #include "enc_dec/asn1.h"
14   #include "enc_dec/asn1_ext.h"
15   #include "envelope/envelope.h"
16 #endif /* Compiler-specific includes */
17 
18 #ifdef USE_ENVELOPES
19 
20 /****************************************************************************
21 *																			*
22 *						Encrypted Content Pre-processing					*
23 *																			*
24 ****************************************************************************/
25 
26 /* Create a context for a particular envelope action type */
27 
28 CHECK_RETVAL_SPECIAL STDC_NONNULL_ARG( ( 1 ) ) \
createActionContext(INOUT ENVELOPE_INFO * envelopeInfoPtr,IN_ENUM (ACTION)const ACTION_TYPE actionType,IN_ALGO const CRYPT_ALGO_TYPE cryptAlgo,IN_HANDLE_OPT const CRYPT_CONTEXT iMasterKeyContext)29 static int createActionContext( INOUT ENVELOPE_INFO *envelopeInfoPtr,
30 								IN_ENUM( ACTION ) const ACTION_TYPE actionType,
31 								IN_ALGO const CRYPT_ALGO_TYPE cryptAlgo,
32 								IN_HANDLE_OPT \
33 									const CRYPT_CONTEXT iMasterKeyContext )
34 	{
35 	CRYPT_CONTEXT iActionContext;
36 	MESSAGE_CREATEOBJECT_INFO createInfo;
37 	int status;
38 
39 	assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
40 
41 	REQUIRES( actionType == ACTION_CRYPT || actionType == ACTION_MAC || \
42 			  actionType == ACTION_xxx );
43 	REQUIRES( isConvAlgo( cryptAlgo ) || isMacAlgo( cryptAlgo ) || \
44 			  isSpecialAlgo( cryptAlgo ) );
45 	REQUIRES( iMasterKeyContext == CRYPT_UNUSED || \
46 			  isHandleRangeValid( iMasterKeyContext ) );
47 
48 	/* Make sure that we can still add another action */
49 	if( !moreActionsPossible( envelopeInfoPtr->actionList ) )
50 		return( CRYPT_ERROR_OVERFLOW );
51 
52 	/* Create a the appropriate context type and either generate a key for
53 	   it if we're using standard encryption/authentication or derive a key
54 	   from the supplied generic-secret context if we're using authenticated
55 	   encryption */
56 	setMessageCreateObjectInfo( &createInfo, cryptAlgo );
57 	status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
58 							  IMESSAGE_DEV_CREATEOBJECT, &createInfo,
59 							  OBJECT_TYPE_CONTEXT );
60 	if( cryptStatusError( status ) )
61 		return( status );
62 	iActionContext = createInfo.cryptHandle;
63 	if( iMasterKeyContext == CRYPT_UNUSED )
64 		{
65 		/* We're using standard encryption or authentication, generate a key
66 		   into the context */
67 		status = krnlSendNotifier( iActionContext, IMESSAGE_CTX_GENKEY );
68 		}
69 	else
70 		{
71 		MECHANISM_KDF_INFO mechanismInfo;
72 
73 		/* We're using authenticated encryption, derive the key for the
74 		   context from the generic-secret context */
75 		if( actionType == ACTION_CRYPT )
76 			{
77 			setMechanismKDFInfo( &mechanismInfo, iActionContext,
78 								 iMasterKeyContext,
79 								 envelopeInfoPtr->defaultMAC,
80 								 "encryption", 10 );
81 			}
82 		else
83 			{
84 			setMechanismKDFInfo( &mechanismInfo, iActionContext,
85 								 iMasterKeyContext,
86 								 envelopeInfoPtr->defaultMAC,
87 								 "authentication", 14 );
88 			}
89 		status = krnlSendMessage( SYSTEM_OBJECT_HANDLE, IMESSAGE_DEV_KDF,
90 								  &mechanismInfo, MECHANISM_DERIVE_PKCS5 );
91 		}
92 	if( cryptStatusError( status ) )
93 		{
94 		krnlSendNotifier( iActionContext, IMESSAGE_DECREFCOUNT );
95 		return( status );
96 		}
97 
98 	/* Add the context to the action list */
99 	status = addAction( &envelopeInfoPtr->actionList,
100 						envelopeInfoPtr->memPoolState, actionType,
101 						iActionContext );
102 	if( cryptStatusError( status ) )
103 		{
104 		krnlSendNotifier( iActionContext, IMESSAGE_DECREFCOUNT );
105 		return( status );
106 		}
107 
108 	return( CRYPT_OK );
109 	}
110 
111 /* Create the contexts needed for the enveloping process */
112 
113 CHECK_RETVAL_SPECIAL STDC_NONNULL_ARG( ( 1 ) ) \
createEnvelopeContexts(INOUT ENVELOPE_INFO * envelopeInfoPtr)114 static int createEnvelopeContexts( INOUT ENVELOPE_INFO *envelopeInfoPtr )
115 	{
116 	ACTION_LIST *actionListPtr;
117 	int status;
118 
119 	REQUIRES( envelopeInfoPtr->actionList == NULL );
120 
121 	switch( envelopeInfoPtr->usage )
122 		{
123 		case ACTION_CRYPT:
124 			/* If we're performing straight encryption, there's only one
125 			   context to create */
126 			if( !( envelopeInfoPtr->flags & ENVELOPE_AUTHENC ) )
127 				{
128 				return( createActionContext( envelopeInfoPtr, ACTION_CRYPT,
129 											 envelopeInfoPtr->defaultAlgo,
130 											 CRYPT_UNUSED ) );
131 				}
132 
133 			/* We're performing authenticated encryption, we need to create
134 			   a generic-secret context for the master secret and separate
135 			   encryption and MAC contexts to provide the protection */
136 			status = createActionContext( envelopeInfoPtr, ACTION_xxx,
137 										  CRYPT_IALGO_GENERIC_SECRET,
138 										  CRYPT_UNUSED );
139 			if( cryptStatusError( status ) )
140 				return( status );
141 			actionListPtr = findAction( envelopeInfoPtr->actionList,
142 										ACTION_xxx );
143 			REQUIRES( actionListPtr != NULL );
144 			status = createActionContext( envelopeInfoPtr, ACTION_CRYPT,
145 										  envelopeInfoPtr->defaultAlgo,
146 										  actionListPtr->iCryptHandle );
147 			if( cryptStatusOK( status ) )
148 				status = createActionContext( envelopeInfoPtr, ACTION_MAC,
149 											  envelopeInfoPtr->defaultMAC,
150 											  actionListPtr->iCryptHandle );
151 			return( status );
152 
153 		case ACTION_MAC:
154 			return( createActionContext( envelopeInfoPtr, ACTION_MAC,
155 										 envelopeInfoPtr->defaultMAC,
156 										 CRYPT_UNUSED ) );
157 
158 		default:
159 			retIntError();
160 		}
161 
162 	retIntError();
163 	}
164 
165 /* Process an individual key exchange action for teh main envelope action */
166 
167 CHECK_RETVAL_SPECIAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
processKeyexchangeAction(INOUT ENVELOPE_INFO * envelopeInfoPtr,INOUT ACTION_LIST * preActionListPtr,IN_HANDLE_OPT const CRYPT_DEVICE iCryptDevice)168 static int processKeyexchangeAction( INOUT ENVELOPE_INFO *envelopeInfoPtr,
169 									 INOUT ACTION_LIST *preActionListPtr,
170 									 IN_HANDLE_OPT \
171 										const CRYPT_DEVICE iCryptDevice )
172 	{
173 	ACTION_LIST *actionListPtr = envelopeInfoPtr->actionList;
174 	int keyexAlgorithm DUMMY_INIT, status;
175 
176 	assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
177 	assert( isWritePtr( preActionListPtr, sizeof( ACTION_LIST ) ) );
178 
179 	REQUIRES( preActionListPtr != NULL && \
180 			  ( preActionListPtr->action == ACTION_KEYEXCHANGE_PKC || \
181 				preActionListPtr->action == ACTION_KEYEXCHANGE ) );
182 	REQUIRES( iCryptDevice == CRYPT_UNUSED || \
183 			  isHandleRangeValid( iCryptDevice ) );
184 	REQUIRES( actionListPtr != NULL );
185 
186 	/* If the session key/MAC/generic-secret context is tied to a device
187 	   make sure that the key exchange object is in the same device */
188 	if( iCryptDevice != CRYPT_UNUSED )
189 		{
190 		CRYPT_DEVICE iKeyexDevice;
191 
192 		status = krnlSendMessage( preActionListPtr->iCryptHandle,
193 								  MESSAGE_GETDEPENDENT, &iKeyexDevice,
194 								  OBJECT_TYPE_DEVICE );
195 		if( cryptStatusError( status ) || iCryptDevice != iKeyexDevice )
196 			{
197 			setErrorInfo( envelopeInfoPtr,
198 						  ( envelopeInfoPtr->usage == ACTION_CRYPT ) ? \
199 							CRYPT_ENVINFO_SESSIONKEY : CRYPT_ENVINFO_INTEGRITY,
200 						  CRYPT_ERRTYPE_CONSTRAINT );
201 			return( CRYPT_ERROR_INVALID );
202 			}
203 		}
204 
205 	/* Remember that we now have a controlling action and connect the
206 	   controller to the subject */
207 	actionListPtr->flags &= ~ACTION_NEEDSCONTROLLER;
208 	preActionListPtr->associatedAction = actionListPtr;
209 
210 	/* Evaluate the size of the exported action.  If it's a conventional key
211 	   exchange we force the use of the CMS format since there's no reason
212 	   to use the cryptlib format.  Note that this assumes that the first
213 	   action is the one that we'll be exporting the key for, which is
214 	   required for authenticated encryption where there can be multiple
215 	   actions (one for encryption and one for authentication) alongside the
216 	   generic-secret action present */
217 	status = iCryptExportKey( NULL, 0, &preActionListPtr->encodedSize,
218 						( preActionListPtr->action == ACTION_KEYEXCHANGE ) ? \
219 							CRYPT_FORMAT_CMS : envelopeInfoPtr->type,
220 						actionListPtr->iCryptHandle,
221 						preActionListPtr->iCryptHandle );
222 	if( cryptStatusOK( status ) )
223 		{
224 		status = krnlSendMessage( preActionListPtr->iCryptHandle,
225 								  IMESSAGE_GETATTRIBUTE, &keyexAlgorithm,
226 								  CRYPT_CTXINFO_ALGO );
227 		}
228 	if( cryptStatusError( status ) )
229 		return( status );
230 
231 	/* If there are any key exchange actions that will result in indefinite-
232 	   length encodings present we can't use a definite-length encoding for
233 	   the key exchange actions */
234 	return( ( isDlpAlgo( keyexAlgorithm ) || \
235 			  isEccAlgo( keyexAlgorithm ) ) ? OK_SPECIAL : CRYPT_OK );
236 	}
237 
238 /* Pre-process information for encrypted enveloping */
239 
240 CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
cmsPreEnvelopeEncrypt(INOUT ENVELOPE_INFO * envelopeInfoPtr)241 int cmsPreEnvelopeEncrypt( INOUT ENVELOPE_INFO *envelopeInfoPtr )
242 	{
243 	CRYPT_DEVICE iCryptDevice = CRYPT_UNUSED;
244 	ACTION_LIST *actionListPtr;
245 	BOOLEAN hasIndefSizeActions = FALSE;
246 	int totalSize, iterationCount, status;
247 
248 	assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
249 
250 	REQUIRES( envelopeInfoPtr->usage == ACTION_CRYPT || \
251 			  envelopeInfoPtr->usage == ACTION_MAC );
252 
253 	/* If there are no key exchange actions present we're done */
254 	if( envelopeInfoPtr->preActionList == NULL )
255 		return( CRYPT_OK );
256 
257 	/* Create the enveloping context(s) if necessary */
258 	if( envelopeInfoPtr->actionList == NULL )
259 		{
260 		status = createEnvelopeContexts( envelopeInfoPtr );
261 		if( cryptStatusError( status ) )
262 			return( status );
263 		}
264 	else
265 		{
266 		/* If the encryption/MAC context is tied to a device get its handle
267 		   so that we can check that all key exchange objects are also in the
268 		   same device.
269 
270 		   In theory if we're using a device for our crypto and performing
271 		   authenticated encryption then we'd need to check that all of the
272 		   generic-secret, encryption and MAC contexts are contained in the
273 		   same device, however since we don't allow these to be explicitly
274 		   set by the user (the encryption and MAC keys are derived from the
275 		   generic-secret context so it's not possible to set a key-loaded
276 		   encryption/MAC context) this can never occur */
277 		REQUIRES( envelopeInfoPtr->actionList->next == NULL );
278 		status = krnlSendMessage( envelopeInfoPtr->actionList->iCryptHandle,
279 								  MESSAGE_GETDEPENDENT, &iCryptDevice,
280 								  OBJECT_TYPE_DEVICE );
281 		if( cryptStatusError( status ) )
282 			iCryptDevice = CRYPT_UNUSED;
283 		}
284 	REQUIRES( envelopeInfoPtr->actionList != NULL );
285 
286 	/* If we're performing straight encryption or MACing, notify the kernel
287 	   that the encryption/MAC context is attached to the envelope.  This is
288 	   an internal object used only by the envelope so we tell the kernel
289 	   not to increment its reference count when it attaches it.  If we're
290 	   performing authenticated encryption then we can't do this because
291 	   we're going via an intermediate generic-secret object from which keys
292 	   will be diversified into distinct encryption and MAC objects */
293 	if( !( envelopeInfoPtr->usage == ACTION_CRYPT && \
294 		   ( envelopeInfoPtr->flags & ENVELOPE_AUTHENC ) ) )
295 		{
296 		REQUIRES( envelopeInfoPtr->actionList->next == NULL );
297 
298 		status = krnlSendMessage( envelopeInfoPtr->objectHandle,
299 								  IMESSAGE_SETDEPENDENT,
300 								  &envelopeInfoPtr->actionList->iCryptHandle,
301 								  SETDEP_OPTION_NOINCREF );
302 		if( cryptStatusError( status ) )
303 			return( status );
304 		}
305 
306 	/* Now walk down the list of key exchange actions evaluating their size
307 	   and connecting each one to the encryption/MAC/generic-secret action */
308 	totalSize = 0;
309 	for( actionListPtr = envelopeInfoPtr->preActionList, iterationCount = 0;
310 		 actionListPtr != NULL && iterationCount < FAILSAFE_ITERATIONS_MED;
311 		 actionListPtr = actionListPtr->next, iterationCount++ )
312 		{
313 		status = processKeyexchangeAction( envelopeInfoPtr, actionListPtr,
314 										   iCryptDevice );
315 		if( cryptStatusError( status ) )
316 			{
317 			/* An OK_SPECIAL state means that this keyex action will result
318 			   in an indefinite-length encoding */
319 			if( status != OK_SPECIAL )
320 				return( status );
321 			hasIndefSizeActions = TRUE;
322 			}
323 		totalSize += actionListPtr->encodedSize;
324 		}
325 	ENSURES( iterationCount < FAILSAFE_ITERATIONS_MED );
326 	envelopeInfoPtr->cryptActionSize = hasIndefSizeActions ? \
327 									   CRYPT_UNUSED : totalSize;
328 	ENSURES( ( envelopeInfoPtr->cryptActionSize == CRYPT_UNUSED ) || \
329 			 ( envelopeInfoPtr->cryptActionSize > 0 && \
330 			   envelopeInfoPtr->cryptActionSize < MAX_BUFFER_SIZE ) );
331 
332 	/* If we're MACing the data (either directly or because we're performing
333 	   authenticated encryption), hashing is now active.  The two actions
334 	   have different flags because standalone MACing hashes plaintext while
335 	   MACing as part of authenticated encryption hashes ciphertext */
336 	if( envelopeInfoPtr->usage == ACTION_MAC )
337 		envelopeInfoPtr->dataFlags |= ENVDATA_HASHACTIONSACTIVE;
338 	if( envelopeInfoPtr->usage == ACTION_CRYPT && \
339 		( envelopeInfoPtr->flags & ENVELOPE_AUTHENC ) )
340 		envelopeInfoPtr->dataFlags |= ENVDATA_AUTHENCACTIONSACTIVE;
341 
342 	return( CRYPT_OK );
343 	}
344 
345 /****************************************************************************
346 *																			*
347 *						Signed Content Pre-processing						*
348 *																			*
349 ****************************************************************************/
350 
351 /* Set up signature parameters such as signature attributes and timestamps
352    if necessary */
353 
354 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 4 ) ) \
cmsInitSigParams(const ACTION_LIST * actionListPtr,IN_ENUM (CRYPT_FORMAT)const CRYPT_FORMAT_TYPE formatType,IN_HANDLE const CRYPT_USER iCryptOwner,OUT SIGPARAMS * sigParams)355 int cmsInitSigParams( const ACTION_LIST *actionListPtr,
356 					  IN_ENUM( CRYPT_FORMAT ) const CRYPT_FORMAT_TYPE formatType,
357 					  IN_HANDLE const CRYPT_USER iCryptOwner,
358 					  OUT SIGPARAMS *sigParams )
359 	{
360 	const CRYPT_CERTIFICATE signingAttributes = actionListPtr->iExtraData;
361 	int useDefaultAttributes, status;
362 
363 	REQUIRES( formatType == CRYPT_FORMAT_CRYPTLIB || \
364 			  formatType == CRYPT_FORMAT_CMS || \
365 			  formatType == CRYPT_FORMAT_SMIME );
366 	REQUIRES( iCryptOwner == DEFAULTUSER_OBJECT_HANDLE || \
367 			  isHandleRangeValid( iCryptOwner ) );
368 
369 	assert( isReadPtr( actionListPtr, sizeof( ACTION_LIST ) ) );
370 	assert( isWritePtr( sigParams, sizeof( SIGPARAMS ) ) );
371 
372 	initSigParams( sigParams );
373 
374 	/* If it's a raw signature there are no additional signing parameters */
375 	if( formatType == CRYPT_FORMAT_CRYPTLIB )
376 		return( CRYPT_OK );
377 
378 	/* Add the timestamping session if there's one present */
379 	if( actionListPtr->iTspSession != CRYPT_ERROR )
380 		sigParams->iTspSession = actionListPtr->iTspSession;
381 
382 	/* If the caller has provided signing attributes, use those */
383 	if( signingAttributes != CRYPT_ERROR )
384 		{
385 		sigParams->iAuthAttr = signingAttributes;
386 		return( CRYPT_OK );
387 		}
388 
389 	/* There are no siging attributes explicitly specified (which can only
390 	   happen under circumstances controlled by the pre-envelope signing
391 	   code) in which case we either get the signing code to add the default
392 	   ones for us or use none at all if the use of default attributes is
393 	   disabled */
394 	status = krnlSendMessage( iCryptOwner, IMESSAGE_GETATTRIBUTE,
395 							  &useDefaultAttributes,
396 							  CRYPT_OPTION_CMS_DEFAULTATTRIBUTES );
397 	if( cryptStatusError( status ) )
398 		return( status );
399 	if( useDefaultAttributes )
400 		sigParams->useDefaultAuthAttr = TRUE;
401 
402 	return( CRYPT_OK );
403 	}
404 
405 /* Process signing certificates and match the content-type in the
406    authenticated attributes with the signed content type if it's anything
407    other than 'data' (the data content-type is added automatically) */
408 
409 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
processSigningCerts(INOUT ENVELOPE_INFO * envelopeInfoPtr,INOUT ACTION_LIST * actionListPtr)410 static int processSigningCerts( INOUT ENVELOPE_INFO *envelopeInfoPtr,
411 							    INOUT ACTION_LIST *actionListPtr )
412 	{
413 	int contentType, dummy, status;
414 
415 	assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
416 	assert( isWritePtr( actionListPtr, sizeof( ACTION_LIST ) ) );
417 
418 	/* If we're including signing certificates and there are multiple
419 	   signing certificates present add the currently-selected one to the
420 	   overall certificate collection */
421 	if( !( envelopeInfoPtr->flags & ENVELOPE_NOSIGNINGCERTS ) && \
422 		envelopeInfoPtr->iExtraCertChain != CRYPT_ERROR )
423 		{
424 		status = krnlSendMessage( envelopeInfoPtr->iExtraCertChain,
425 								  IMESSAGE_SETATTRIBUTE,
426 								  &actionListPtr->iCryptHandle,
427 								  CRYPT_IATTRIBUTE_CERTCOLLECTION );
428 		if( cryptStatusError( status ) )
429 			return( status );
430 		}
431 
432 	/* If there's no content-type present and the signed content type isn't
433 	   'data' or it's an S/MIME envelope, create signing attributes to hold
434 	   the content-type and smimeCapabilities */
435 	if( actionListPtr->iExtraData == CRYPT_ERROR && \
436 		( envelopeInfoPtr->contentType != CRYPT_CONTENT_DATA || \
437 		  envelopeInfoPtr->type == CRYPT_FORMAT_SMIME ) )
438 		{
439 		MESSAGE_CREATEOBJECT_INFO createInfo;
440 
441 		setMessageCreateObjectInfo( &createInfo,
442 									CRYPT_CERTTYPE_CMS_ATTRIBUTES );
443 		status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
444 								  IMESSAGE_DEV_CREATEOBJECT,
445 								  &createInfo, OBJECT_TYPE_CERTIFICATE );
446 		if( cryptStatusError( status ) )
447 			return( status );
448 		actionListPtr->iExtraData = createInfo.cryptHandle;
449 		}
450 
451 	/* If there are no signed attributes, we're done */
452 	if( actionListPtr->iExtraData == CRYPT_ERROR )
453 		return( CRYPT_OK );
454 
455 	/* Make sure that the content-type in the attributes matches the actual
456 	   content type by deleting any existing content-type if necessary and
457 	   adding our one (quietly fixing things is easier than trying to report
458 	   this error back to the caller - ex duobus malis minimum eligendum
459 	   est) */
460 	if( krnlSendMessage( actionListPtr->iExtraData,
461 						 IMESSAGE_GETATTRIBUTE, &dummy,
462 						 CRYPT_CERTINFO_CMS_CONTENTTYPE ) != CRYPT_ERROR_NOTFOUND )
463 		{
464 		/* There's already a content-type present, delete it so that we can
465 		   add our one.  We ignore the return status from the deletion since
466 		   the status from the add that follows will be more meaningful to
467 		   the caller */
468 		( void ) krnlSendMessage( actionListPtr->iExtraData,
469 								  IMESSAGE_DELETEATTRIBUTE, NULL,
470 								  CRYPT_CERTINFO_CMS_CONTENTTYPE );
471 		}
472 	contentType = envelopeInfoPtr->contentType;	/* int vs.enum */
473 	return( krnlSendMessage( actionListPtr->iExtraData,
474 							 IMESSAGE_SETATTRIBUTE, &contentType,
475 							 CRYPT_CERTINFO_CMS_CONTENTTYPE ) );
476 	}
477 
478 /* Pre-process information for signed enveloping */
479 
480 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
processSignatureAction(INOUT ENVELOPE_INFO * envelopeInfoPtr,INOUT ACTION_LIST * actionListPtr)481 static int processSignatureAction( INOUT ENVELOPE_INFO *envelopeInfoPtr,
482 								   INOUT ACTION_LIST *actionListPtr )
483 	{
484 	SIGPARAMS sigParams;
485 	int signatureAlgo DUMMY_INIT, signatureSize, status;
486 
487 	assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
488 	assert( isWritePtr( actionListPtr, sizeof( ACTION_LIST ) ) );
489 
490 	REQUIRES( actionListPtr != NULL && \
491 			  actionListPtr->action == ACTION_SIGN && \
492 			  actionListPtr->associatedAction != NULL );
493 
494 	/* Process signing certificates and fix up the content-type in the
495 	   authenticated attributes if necessary */
496 	if( envelopeInfoPtr->type == CRYPT_FORMAT_CMS || \
497 		envelopeInfoPtr->type == CRYPT_FORMAT_SMIME )
498 		{
499 		status = processSigningCerts( envelopeInfoPtr, actionListPtr );
500 		if( cryptStatusError( status ) )
501 			return( status );
502 		}
503 
504 	/* Set up any necessary signature parameters such as signature
505 	  attributes and timestamps if necessary */
506 	status = cmsInitSigParams( actionListPtr, envelopeInfoPtr->type,
507 							   envelopeInfoPtr->ownerHandle,
508 							   &sigParams );
509 	if( cryptStatusError( status ) )
510 		return( status );
511 
512 	/* Evaluate the size of the exported action */
513 	status = iCryptCreateSignature( NULL, 0, &signatureSize,
514 						envelopeInfoPtr->type, actionListPtr->iCryptHandle,
515 						actionListPtr->associatedAction->iCryptHandle,
516 						( envelopeInfoPtr->type == CRYPT_FORMAT_CRYPTLIB ) ? \
517 							NULL : &sigParams );
518 	if( cryptStatusOK( status ) )
519 		{
520 		status = krnlSendMessage( actionListPtr->iCryptHandle,
521 								  IMESSAGE_GETATTRIBUTE, &signatureAlgo,
522 								  CRYPT_CTXINFO_ALGO );
523 		}
524 	if( cryptStatusError( status ) )
525 		return( status );
526 	if( isDlpAlgo( signatureAlgo ) || isEccAlgo( signatureAlgo ) || \
527 		actionListPtr->iTspSession != CRYPT_ERROR )
528 		{
529 		/* If there are any signature actions that will result in indefinite-
530 		   length encodings present then we can't use a definite-length
531 		   encoding for the signature */
532 		envelopeInfoPtr->dataFlags |= ENVDATA_HASINDEFTRAILER;
533 		actionListPtr->encodedSize = CRYPT_UNUSED;
534 		}
535 	else
536 		{
537 		actionListPtr->encodedSize = signatureSize;
538 		envelopeInfoPtr->signActionSize += signatureSize;
539 		}
540 	if( envelopeInfoPtr->dataFlags & ENVDATA_HASINDEFTRAILER )
541 		envelopeInfoPtr->signActionSize = CRYPT_UNUSED;
542 	ENSURES( ( envelopeInfoPtr->signActionSize == CRYPT_UNUSED ) || \
543 			 ( envelopeInfoPtr->signActionSize > 0 && \
544 			   envelopeInfoPtr->signActionSize < MAX_BUFFER_SIZE ) );
545 
546 	return( CRYPT_OK );
547 	}
548 
549 CHECK_RETVAL STDC_NONNULL_ARG( ( 1 ) ) \
cmsPreEnvelopeSign(INOUT ENVELOPE_INFO * envelopeInfoPtr)550 int cmsPreEnvelopeSign( INOUT ENVELOPE_INFO *envelopeInfoPtr )
551 	{
552 	ACTION_LIST *actionListPtr = envelopeInfoPtr->postActionList;
553 	int iterationCount, status;
554 
555 	assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
556 
557 	REQUIRES( envelopeInfoPtr->usage == ACTION_SIGN );
558 	REQUIRES( actionListPtr != NULL && \
559 			  actionListPtr->associatedAction != NULL );
560 
561 	/* If we're generating a detached signature the content is supplied
562 	   externally and has zero size */
563 	if( envelopeInfoPtr->flags & ENVELOPE_DETACHED_SIG )
564 		envelopeInfoPtr->payloadSize = 0;
565 
566 	/* If it's an attributes-only message it must be zero-length CMS signed
567 	   data with signing attributes present */
568 	if( envelopeInfoPtr->flags & ENVELOPE_ATTRONLY )
569 		{
570 		if( envelopeInfoPtr->type != CRYPT_FORMAT_CMS || \
571 			actionListPtr->iExtraData == CRYPT_ERROR )
572 			{
573 			setErrorInfo( envelopeInfoPtr, CRYPT_ENVINFO_SIGNATURE_EXTRADATA,
574 						  CRYPT_ERRTYPE_ATTR_ABSENT );
575 			return( CRYPT_ERROR_NOTINITED );
576 			}
577 		if( envelopeInfoPtr->payloadSize > 0 )
578 			{
579 			setErrorInfo( envelopeInfoPtr, CRYPT_ENVINFO_DATASIZE,
580 						  CRYPT_ERRTYPE_ATTR_VALUE );
581 			return( CRYPT_ERROR_INITED );
582 			}
583 		}
584 
585 	/* If it's a CMS envelope we have to write the signing certificate chain
586 	   alongside the signatures as extra data unless it's explicitly
587 	   excluded so we record how large the information will be for later */
588 	if( ( envelopeInfoPtr->type == CRYPT_FORMAT_CMS || \
589 		  envelopeInfoPtr->type == CRYPT_FORMAT_SMIME ) && \
590 		!( envelopeInfoPtr->flags & ENVELOPE_NOSIGNINGCERTS ) )
591 		{
592 		if( actionListPtr->next != NULL )
593 			{
594 			MESSAGE_CREATEOBJECT_INFO createInfo;
595 
596 			/* There are multiple sets of signing certificates present,
597 			   create a signing-certificate meta-object to hold the overall
598 			   set of certificates */
599 			setMessageCreateObjectInfo( &createInfo,
600 										CRYPT_CERTTYPE_CERTCHAIN );
601 			status = krnlSendMessage( SYSTEM_OBJECT_HANDLE,
602 									  IMESSAGE_DEV_CREATEOBJECT,
603 									  &createInfo, OBJECT_TYPE_CERTIFICATE );
604 			if( cryptStatusError( status ) )
605 				return( status );
606 			envelopeInfoPtr->iExtraCertChain = createInfo.cryptHandle;
607 			}
608 		else
609 			{
610 			MESSAGE_DATA msgData;
611 
612 			/* There's a single signing certificate present, determine its
613 			   size */
614 			setMessageData( &msgData, NULL, 0 );
615 			status = krnlSendMessage( actionListPtr->iCryptHandle,
616 									  IMESSAGE_CRT_EXPORT, &msgData,
617 									  CRYPT_ICERTFORMAT_CERTSET );
618 			if( cryptStatusError( status ) )
619 				return( status );
620 			envelopeInfoPtr->extraDataSize = msgData.length;
621 			}
622 		}
623 
624 	/* Evaluate the size of each signature action */
625 	for( actionListPtr = envelopeInfoPtr->postActionList, iterationCount = 0;
626 		 actionListPtr != NULL && iterationCount < FAILSAFE_ITERATIONS_MED;
627 		 actionListPtr = actionListPtr->next, iterationCount++ )
628 		{
629 		status = processSignatureAction( envelopeInfoPtr, actionListPtr );
630 		if( cryptStatusError( status ) )
631 			return( status );
632 		}
633 	ENSURES( iterationCount < FAILSAFE_ITERATIONS_MED );
634 
635 	/* If we're writing the signing certificate chain and there are multiple
636 	   signing certificates present, get the size of the overall certificate
637 	   collection */
638 	if( envelopeInfoPtr->iExtraCertChain != CRYPT_ERROR )
639 		{
640 		MESSAGE_DATA msgData;
641 
642 		setMessageData( &msgData, NULL, 0 );
643 		status = krnlSendMessage( envelopeInfoPtr->iExtraCertChain,
644 								  IMESSAGE_CRT_EXPORT, &msgData,
645 								  CRYPT_ICERTFORMAT_CERTSET );
646 		if( cryptStatusError( status ) )
647 			return( status );
648 		envelopeInfoPtr->extraDataSize = msgData.length;
649 		}
650 	ENSURES( envelopeInfoPtr->extraDataSize >= 0 && \
651 			 envelopeInfoPtr->extraDataSize < MAX_BUFFER_SIZE );
652 
653 	/* Hashing is now active (you have no chance to survive make your
654 	   time) */
655 	envelopeInfoPtr->dataFlags |= ENVDATA_HASHACTIONSACTIVE;
656 
657 	return( CRYPT_OK );
658 	}
659 #endif /* USE_ENVELOPES */
660