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