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