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