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