cryptlib  3.4.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros
res_env.c
Go to the documentation of this file.
1 /****************************************************************************
2 * *
3 * cryptlib 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 #ifdef USE_ENVELOPES
21 
22 /****************************************************************************
23 * *
24 * Utility Functions *
25 * *
26 ****************************************************************************/
27 
28 #ifdef USE_PGP
29 
30 /* Check that an object being added is suitable for use with PGP data */
31 
33 static int checkPgpUsage( INOUT ENVELOPE_INFO *envelopeInfoPtr,
35  {
36  assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
37 
38  REQUIRES( envInfo > CRYPT_ENVINFO_FIRST && envInfo < CRYPT_ENVINFO_LAST );
39 
40  /* The attribute being added isn't context-related, there's nothing
41  PGP-specific to check */
42  if( envInfo != CRYPT_ENVINFO_PUBLICKEY && \
43  envInfo != CRYPT_ENVINFO_PRIVATEKEY && \
44  envInfo != CRYPT_ENVINFO_KEY && \
45  envInfo != CRYPT_ENVINFO_SESSIONKEY && \
46  envInfo != CRYPT_ENVINFO_HASH && \
47  envInfo != CRYPT_ENVINFO_SIGNATURE )
48  return( CRYPT_OK );
49 
50  /* PGP doesn't support both PKC and conventional key exchange actions in
51  the same envelope since the session key is encrypted for the PKC
52  action but derived from the password for the conventional action */
53  if( findAction( envelopeInfoPtr->preActionList,
54  ACTION_KEYEXCHANGE ) != NULL )
55  return( CRYPT_ERROR_INITED );
56 
57  /* PGP handles multiple signers by nesting signed data rather than
58  attaching multiple signatures so we can only apply a single
59  signature per envelope */
60  if( envInfo == CRYPT_ENVINFO_SIGNATURE && \
61  envelopeInfoPtr->postActionList != NULL )
62  return( CRYPT_ERROR_INITED );
63 
64  /* PGP doesn't allow multiple hash algorithms to be used when signing
65  data, a follow-on from the way that nested sigs are handled */
66  if( envInfo == CRYPT_ENVINFO_HASH && \
67  envelopeInfoPtr->actionList != NULL )
68  return( CRYPT_ERROR_INITED );
69 
70  return( CRYPT_OK );
71  }
72 #endif /* USE_PGP */
73 
74 /****************************************************************************
75 * *
76 * Misc.Enveloping Info Management Functions *
77 * *
78 ****************************************************************************/
79 
80 /* Set up the encryption for an envelope */
81 
83 int initEnvelopeEncryption( INOUT ENVELOPE_INFO *envelopeInfoPtr,
87  IN_BUFFER_OPT( ivLength ) const BYTE *iv,
88  IN_LENGTH_IV_Z const int ivLength,
89  const BOOLEAN copyContext )
90  {
92  int contextAlgorithm = DUMMY_INIT, contextMode = DUMMY_INIT;
94 
95  assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
96  assert( ( iv == NULL && ivLength == 0 ) || \
97  isReadPtr( iv, ivLength ) );
98 
99  REQUIRES( isHandleRangeValid( cryptContext ) );
100  REQUIRES( ( algorithm == CRYPT_ALGO_NONE && mode == CRYPT_MODE_NONE ) || \
101  ( isConvAlgo( algorithm ) ) );
102  REQUIRES( ( algorithm == CRYPT_ALGO_NONE && mode == CRYPT_MODE_NONE ) || \
103  ( mode > CRYPT_MODE_NONE && mode < CRYPT_MODE_LAST ) );
104  REQUIRES( ( iv == NULL && ivLength == 0 ) || \
105  ( iv != NULL && \
106  ivLength >= 8 && ivLength <= CRYPT_MAX_IVSIZE ) );
107 
108  /* Extract the information that we need to process data */
109  status = krnlSendMessage( cryptContext, IMESSAGE_GETATTRIBUTE,
110  &contextAlgorithm, CRYPT_CTXINFO_ALGO );
111  if( cryptStatusOK( status ) )
112  status = krnlSendMessage( cryptContext, IMESSAGE_GETATTRIBUTE,
113  &contextMode, CRYPT_CTXINFO_MODE );
114  if( cryptStatusOK( status ) )
115  status = krnlSendMessage( cryptContext, IMESSAGE_GETATTRIBUTE,
116  &blockSize, CRYPT_CTXINFO_BLOCKSIZE );
117  if( cryptStatusError( status ) )
118  return( status );
119 
120  /* Make sure that the context is what's required */
121  if( algorithm != CRYPT_ALGO_NONE && \
122  ( contextAlgorithm != algorithm || contextMode != mode ) )
123  {
124  /* This can only happen on de-enveloping if the data is corrupted or
125  if the user is asked for a KEK and tries to supply a session key
126  instead */
127  return( CRYPT_ERROR_WRONGKEY );
128  }
129  if( ivLength != 0 && ivLength != blockSize )
130  return( CRYPT_ERROR_BADDATA );
131 
132  /* If it's a user-supplied context take a copy for our own use. This is
133  only done for non-idempotent user-supplied contexts, for everything
134  else we either use cryptlib's object management to handle things for
135  us or the context is a internal one created specifically for our own
136  use */
137  if( copyContext )
138  {
139  MESSAGE_CREATEOBJECT_INFO createInfo;
140 
141  setMessageCreateObjectInfo( &createInfo, contextAlgorithm );
143  IMESSAGE_DEV_CREATEOBJECT, &createInfo,
145  if( cryptStatusError( status ) )
146  return( status );
147  status = krnlSendMessage( iCryptContext, IMESSAGE_CLONE, NULL,
148  createInfo.cryptHandle );
149  if( cryptStatusError( status ) )
150  {
152  return( status );
153  }
154  iCryptContext = createInfo.cryptHandle;
155  }
156 
157  /* Load the IV into the context and set up the encryption information for
158  the envelope */
159  if( !isStreamCipher( contextAlgorithm ) )
160  {
161  if( iv != NULL )
162  {
164 
165  setMessageData( &msgData, ( MESSAGE_CAST ) iv, ivLength );
166  status = krnlSendMessage( iCryptContext, IMESSAGE_SETATTRIBUTE_S,
167  &msgData, CRYPT_CTXINFO_IV );
168  }
169  else
170  {
171  /* There's no IV specified, generate a new one */
172  status = krnlSendNotifier( iCryptContext, IMESSAGE_CTX_GENIV );
173  }
174  if( cryptStatusError( status ) )
175  {
176  if( copyContext )
177  {
178  /* Destroy the copy that we created earlier */
179  krnlSendNotifier( iCryptContext, IMESSAGE_DECREFCOUNT );
180  }
181  return( status );
182  }
183  }
184  envelopeInfoPtr->iCryptContext = iCryptContext;
185  envelopeInfoPtr->blockSize = blockSize;
186  envelopeInfoPtr->blockSizeMask = ~( blockSize - 1 );
187 
188  return( CRYPT_OK );
189  }
190 
191 /* Check the consistency of enveloping resources before we begin enveloping,
192  returning the ID of any missing attributes */
193 
195 static int checkSignatureActionFunction( const ACTION_LIST *actionListPtr,
196  IN_INT_Z const int signingKeyPresent )
197  {
198  assert( isReadPtr( actionListPtr, sizeof( ACTION_LIST ) ) );
199 
200  /* If there are no signature-related auxiliary options present, there's
201  nothing to check */
202  if( actionListPtr->iExtraData != CRYPT_ERROR || \
203  actionListPtr->iTspSession != CRYPT_ERROR )
204  return( CRYPT_OK );
205 
206  /* There must be a signing key present to handle the signature options */
207  if( !signingKeyPresent || actionListPtr->iCryptHandle == CRYPT_ERROR )
208  return( CRYPT_ERROR_NOTINITED );
209 
210  return( CRYPT_OK );
211  }
212 
214 static int checkMissingInfo( INOUT ENVELOPE_INFO *envelopeInfoPtr )
215  {
216  BOOLEAN signingKeyPresent = FALSE;
217 
218  assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
219 
220  /* Make sure that we have the minimum requirements for each usage type
221  present */
222  switch( envelopeInfoPtr->usage )
223  {
224  case ACTION_COMPRESS:
225  REQUIRES( envelopeInfoPtr->flags & ENVELOPE_ZSTREAMINITED );
226  break;
227 
228  case ACTION_HASH:
229  DEBUG_DIAG(( "Hashed (rather than MAC'd) enveloping isn't supported" ));
230  assert( DEBUG_WARN );
231  break;
232 
233  case ACTION_MAC:
234  /* If it's a MAC envelope there must be at least one key exchange
235  action present. A few obscure operation sequences may
236  however set the usage without setting a key exchange action.
237  For example making the envelope a MAC envelope simply
238  indicates that any future key exchange actions should be used
239  for MACing rather than encryption but this is indicative of a
240  logic error in the calling application so we report an error
241  even if, strictly speaking, we could ignore it and continue */
242  if( findAction( envelopeInfoPtr->preActionList, \
243  ACTION_KEYEXCHANGE_PKC ) == NULL && \
244  findAction( envelopeInfoPtr->preActionList, \
245  ACTION_KEYEXCHANGE ) == NULL )
246  {
247  /* We return the most generic CRYPT_ENVINFO_KEY error code
248  since there are several possible missing attribute types
249  that could be required */
250  setErrorInfo( envelopeInfoPtr, CRYPT_ENVINFO_KEY,
252  return( CRYPT_ERROR_NOTINITED );
253  }
254  break;
255 
256  case ACTION_CRYPT:
257  /* If it's an encryption envelope there must be a key present at
258  some level. This situation doesn't normally occur since the
259  higher-level code will only set the usage to encryption once
260  a key exchange action has been added, but we check anyway
261  just to be safe */
262  if( findAction( envelopeInfoPtr->preActionList, \
263  ACTION_KEYEXCHANGE_PKC ) == NULL && \
264  findAction( envelopeInfoPtr->preActionList, \
265  ACTION_KEYEXCHANGE ) == NULL && \
266  findAction( envelopeInfoPtr->actionList, ACTION_CRYPT ) == NULL )
267  {
268  setErrorInfo( envelopeInfoPtr, CRYPT_ENVINFO_KEY,
270  return( CRYPT_ERROR_NOTINITED );
271  }
272  break;
273 
274  case ACTION_SIGN:
275  /* If it's a signing envelope there must be a signature key
276  present */
277  if( findAction( envelopeInfoPtr->postActionList, \
278  ACTION_SIGN ) == NULL )
279  {
280  setErrorInfo( envelopeInfoPtr, CRYPT_ENVINFO_SIGNATURE,
282  return( CRYPT_ERROR_NOTINITED );
283  }
284  signingKeyPresent = TRUE;
285  }
286 
287  REQUIRES( signingKeyPresent || \
288  !( ( envelopeInfoPtr->flags & ENVELOPE_DETACHED_SIG ) || \
289  findAction( envelopeInfoPtr->actionList, ACTION_HASH ) ) );
290 
291  /* If there are signature-related options present (signature envelope,
292  detached-signature flag set, hash context present, or CMS attributes
293  or a TSA session present) there must be a signing key also present */
294  if( envelopeInfoPtr->postActionList != NULL )
295  {
296  int status;
297 
298  status = checkActionIndirect( envelopeInfoPtr->postActionList,
299  checkSignatureActionFunction,
300  signingKeyPresent );
301  if( cryptStatusError( status ) )
302  {
303  setErrorInfo( envelopeInfoPtr, CRYPT_ENVINFO_SIGNATURE,
305  return( status );
306  }
307  }
308 
309  return( CRYPT_OK );
310  }
311 
312 /****************************************************************************
313 * *
314 * Add Enveloping Information *
315 * *
316 ****************************************************************************/
317 
318 /* Add keyset information (this function is also used by the de-enveloping
319  routines) */
320 
322 int addKeysetInfo( INOUT ENVELOPE_INFO *envelopeInfoPtr,
325  const CRYPT_ATTRIBUTE_TYPE keysetFunction,
327  {
328  CRYPT_KEYSET *iKeysetPtr;
329 
330  assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
331 
332  REQUIRES( keysetFunction == CRYPT_ENVINFO_KEYSET_ENCRYPT || \
333  keysetFunction == CRYPT_ENVINFO_KEYSET_DECRYPT || \
334  keysetFunction == CRYPT_ENVINFO_KEYSET_SIGCHECK );
335  REQUIRES( isHandleRangeValid( keyset ) );
336 
337  /* Figure out which keyset we want to set */
338  switch( keysetFunction )
339  {
341  iKeysetPtr = &envelopeInfoPtr->iEncryptionKeyset;
342  break;
343 
345  iKeysetPtr = &envelopeInfoPtr->iDecryptionKeyset;
346  break;
347 
349  iKeysetPtr = &envelopeInfoPtr->iSigCheckKeyset;
350  break;
351 
352  default:
353  retIntError();
354  }
355 
356  /* Make sure that the keyset hasn't already been set */
357  if( *iKeysetPtr != CRYPT_ERROR )
358  {
359  setErrorInfo( envelopeInfoPtr, keysetFunction,
361  return( CRYPT_ERROR_INITED );
362  }
363 
364  /* Remember the new keyset and increment its reference count */
365  *iKeysetPtr = keyset;
366  return( krnlSendNotifier( keyset, IMESSAGE_INCREFCOUNT ) );
367  }
368 
369 /* Add an encryption password */
370 
371 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
372 static int addPasswordInfo( ENVELOPE_INFO *envelopeInfoPtr,
373  IN_BUFFER( passwordLength ) const void *password,
375  const int passwordLength )
376  {
377  CRYPT_ALGO_TYPE cryptAlgo = envelopeInfoPtr->defaultAlgo;
379  MESSAGE_CREATEOBJECT_INFO createInfo;
381  ACTION_RESULT actionResult;
382  int status;
383 
384  assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
385  assert( isReadPtr( password, passwordLength ) );
386 
387  REQUIRES( passwordLength > 0 && passwordLength <= CRYPT_MAX_TEXTSIZE );
388  REQUIRES( envelopeInfoPtr->type != CRYPT_FORMAT_PGP );
389 
390  /* Make sure that we can still add another action */
391  if( !moreActionsPossible( envelopeInfoPtr->preActionList ) )
392  return( CRYPT_ERROR_OVERFLOW );
393 
394  /* Create the appropriate encryption context. We have to be careful to
395  ensure that we use an algorithm which is compatible with the wrapping
396  mechanism */
397  if( isStreamCipher( cryptAlgo ) || \
398  cryptStatusError( sizeofAlgoIDex( cryptAlgo, CRYPT_MODE_CBC, 0 ) ) )
399  cryptAlgo = CRYPT_ALGO_3DES;
400  setMessageCreateObjectInfo( &createInfo, cryptAlgo );
402  &createInfo, OBJECT_TYPE_CONTEXT );
403  if( cryptStatusError( status ) )
404  return( status );
405  iCryptContext = createInfo.cryptHandle;
406 
407  /* Derive the key into the context */
408  setMessageData( &msgData, ( MESSAGE_CAST ) password, passwordLength );
409  status = krnlSendMessage( iCryptContext, IMESSAGE_SETATTRIBUTE_S,
410  &msgData, CRYPT_CTXINFO_KEYING_VALUE );
411  if( cryptStatusError( status ) )
412  {
413  krnlSendNotifier( iCryptContext, IMESSAGE_DECREFCOUNT );
414  return( status );
415  }
416 
417  /* Make sure that this key exchange action isn't already present and
418  insert it into the action list */
419  actionResult = checkAction( envelopeInfoPtr->preActionList,
420  ACTION_KEYEXCHANGE, iCryptContext );
421  if( actionResult == ACTION_RESULT_ERROR || \
422  actionResult == ACTION_RESULT_INITED )
423  {
424  setErrorInfo( envelopeInfoPtr, CRYPT_ENVINFO_PASSWORD,
426  status = CRYPT_ERROR_INITED;
427  }
428  else
429  {
430  status = addAction( &envelopeInfoPtr->preActionList,
431  envelopeInfoPtr->memPoolState,
432  ACTION_KEYEXCHANGE, iCryptContext );
433  }
434  if( cryptStatusError( status ) )
435  krnlSendNotifier( iCryptContext, IMESSAGE_DECREFCOUNT );
436  return( status );
437  }
438 
439 #ifdef USE_PGP
440 
441 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 2 ) ) \
442 static int addPgpPasswordInfo( ENVELOPE_INFO *envelopeInfoPtr,
443  IN_BUFFER( passwordLength ) const void *password,
445  const int passwordLength )
446  {
447  CRYPT_ALGO_TYPE cryptAlgo = envelopeInfoPtr->defaultAlgo;
449  MESSAGE_CREATEOBJECT_INFO createInfo;
451  BYTE salt[ PGP_SALTSIZE + 8 ];
452  static const int mode = CRYPT_MODE_CFB; /* int vs.enum */
453  int status;
454 
455  assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
456  assert( isReadPtr( password, passwordLength ) );
457 
458  REQUIRES( passwordLength > 0 && passwordLength <= CRYPT_MAX_TEXTSIZE );
459  REQUIRES( envelopeInfoPtr->type == CRYPT_FORMAT_PGP );
460 
461  /* Make sure that we can still add another attribute */
462  if( !moreActionsPossible( envelopeInfoPtr->preActionList ) )
463  return( CRYPT_ERROR_OVERFLOW );
464 
465  /* PGP doesn't support both PKC and conventional key exchange actions or
466  multiple conventional key exchange actions in the same envelope since
467  the session key is encrypted for the PKC action but derived from the
468  password for the conventional action */
469  if( envelopeInfoPtr->type == CRYPT_FORMAT_PGP && \
470  ( findAction( envelopeInfoPtr->preActionList,
471  ACTION_KEYEXCHANGE_PKC ) != NULL || \
472  envelopeInfoPtr->actionList != NULL ) )
473  {
474  setErrorInfo( envelopeInfoPtr, CRYPT_ENVINFO_PUBLICKEY,
476  return( CRYPT_ERROR_INITED );
477  }
478 
479  /* Create the appropriate encryption context. PGP wrapping always uses
480  CFB mode (so there are no modes that need to be avoided) and the
481  higher-level code has constrained the algorithm type to something
482  that's encodable using the PGP data format so we don't need to
483  perform any additional checking here */
484  setMessageCreateObjectInfo( &createInfo, cryptAlgo );
486  &createInfo, OBJECT_TYPE_CONTEXT );
487  if( cryptStatusError( status ) )
488  return( status );
489  iCryptContext = createInfo.cryptHandle;
490 
491  /* PGP uses CFB mode for everything so we change the mode from the
492  default of CBC to CFB */
493  status = krnlSendMessage( iCryptContext, IMESSAGE_SETATTRIBUTE,
494  ( MESSAGE_CAST ) &mode, CRYPT_CTXINFO_MODE );
495  if( cryptStatusError( status ) )
496  return( status );
497 
498  /* Generate a salt and derive the key into the context */
499  setMessageData( &msgData, salt, PGP_SALTSIZE );
501  &msgData, CRYPT_IATTRIBUTE_RANDOM_NONCE );
502  if( cryptStatusOK( status ) )
503  {
504  status = pgpPasswordToKey( iCryptContext, CRYPT_UNUSED,
505  password, passwordLength,
506  envelopeInfoPtr->defaultHash,
507  salt, PGP_SALTSIZE, PGP_ITERATIONS );
508  }
509  if( cryptStatusError( status ) )
510  {
511  krnlSendNotifier( iCryptContext, IMESSAGE_DECREFCOUNT );
512  return( status );
513  }
514 
515  /* Insert the context into the action list. Since PGP doesn't perform a
516  key exchange of a session key we insert the password-derived context
517  directly into the main action list */
518  status = addAction( &envelopeInfoPtr->actionList,
519  envelopeInfoPtr->memPoolState, ACTION_CRYPT,
520  iCryptContext );
521  if( cryptStatusError( status ) )
522  krnlSendNotifier( iCryptContext, IMESSAGE_DECREFCOUNT );
523  return( status );
524  }
525 #endif /* USE_PGP */
526 
527 /* Add a context to an envelope */
528 
529 CHECK_RETVAL STDC_NONNULL_ARG( ( 1, 3 ) ) \
530 static int addContextInfo( INOUT ENVELOPE_INFO *envelopeInfoPtr,
533  IN_ENUM( ACTION ) const ACTION_TYPE actionType )
534  {
536  ACTION_LIST *actionListPtr, *hashActionPtr;
537  ACTION_RESULT actionResult;
538  int algorithm, mode = CRYPT_MODE_NONE, certHashAlgo, status;
539 
540  assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
541  assert( isWritePtr( actionListHeadPtrPtr, sizeof( ACTION_LIST * ) ) );
542 
543  REQUIRES( isHandleRangeValid( cryptHandle ) );
544  REQUIRES( actionType > ACTION_NONE && actionType < ACTION_LAST );
545 
546  /* Make sure that we can still add another attribute */
547  if( !moreActionsPossible( envelopeInfoPtr->preActionList ) )
548  return( CRYPT_ERROR_OVERFLOW );
549 
550  /* Make sure that the algorithm information is encodable using the
551  selected envelope format. This should already have been checked by
552  the calling function but we double-check here because this provides
553  a convenient centralised location for it */
554  status = krnlSendMessage( iCryptHandle, IMESSAGE_GETATTRIBUTE,
555  &algorithm, CRYPT_CTXINFO_ALGO );
556  if( cryptStatusOK( status ) && isConvAlgo( algorithm ) )
557  {
558  status = krnlSendMessage( iCryptHandle, IMESSAGE_GETATTRIBUTE,
559  &mode, CRYPT_CTXINFO_MODE );
560  }
561  if( cryptStatusError( status ) )
562  return( status );
563  if( !envelopeInfoPtr->checkAlgo( algorithm, mode ) )
564  return( CRYPT_ARGERROR_NUM1 );
565 
566  /* Find the insertion point for this action and make sure that it isn't
567  already present. The difference between ACTION_RESULT_INITED and
568  ACTION_RESULT_PRESENT is that an inited response indicates that the
569  user explicitly added the action and can't add it again while a
570  present response indicates that the action was added automatically by
571  cryptlib in response to the user adding some other action and
572  shouldn't be reported as an error, to the user it doesn't make any
573  difference whether the same action was added automatically by
574  cryptlib or explicitly */
575  actionResult = checkAction( *actionListHeadPtrPtr, actionType,
576  iCryptHandle );
577  switch( actionResult )
578  {
579  case ACTION_RESULT_OK:
580  case ACTION_RESULT_EMPTY:
581  break;
582 
584  return( CRYPT_ERROR_INITED );
585 
587  return( CRYPT_OK );
588 
589  case ACTION_RESULT_ERROR:
590  return( CRYPT_ARGERROR_NUM1 );
591 
592  default:
593  retIntError();
594  }
595 
596  /* Insert the action into the list. If it's a non-idempotent context
597  (i.e. one whose state can change based on user actions) we clone it
598  for our own use, otherwise we just increment its reference count */
599  if( actionType == ACTION_HASH || actionType == ACTION_CRYPT )
600  {
601  MESSAGE_CREATEOBJECT_INFO createInfo;
602 
603  setMessageCreateObjectInfo( &createInfo, algorithm );
605  IMESSAGE_DEV_CREATEOBJECT, &createInfo,
607  if( cryptStatusError( status ) )
608  return( status );
609  status = krnlSendMessage( iCryptHandle, IMESSAGE_CLONE, NULL,
610  createInfo.cryptHandle );
611  if( cryptStatusError( status ) )
612  {
614  return( status );
615  }
616  iCryptHandle = createInfo.cryptHandle;
617  }
618  else
619  {
620  status = krnlSendNotifier( iCryptHandle, IMESSAGE_INCREFCOUNT );
621  if( cryptStatusError( status ) )
622  return( status );
623  }
624  status = addActionEx( &actionListPtr, actionListHeadPtrPtr,
625  envelopeInfoPtr->memPoolState, actionType,
626  iCryptHandle );
627  if( cryptStatusError( status ) )
628  {
629  krnlSendNotifier( iCryptHandle, IMESSAGE_DECREFCOUNT );
630  return( status );
631  }
632  if( actionType == ACTION_HASH )
633  {
634  /* Remember that we need to hook the hash action up to a signature
635  action before we start enveloping data */
636  actionListPtr->flags |= ACTION_NEEDSCONTROLLER;
637  }
638 
639  /* If the newly-inserted action isn't a controlling action, we're done */
640  if( actionType != ACTION_SIGN )
641  return( status );
642 
643  /* Check whether the hash algorithm used in the certificate attached to
644  the signing key is stronger than the one that's set for the envelope
645  as a whole and if it is, upgrade the envelope hash algo. This is
646  based on the fact that anyone who's able to verify the certificate
647  using a stronger hash algorithm must also be able to verify the
648  envelope using the stronger algorithm. This allows a transparent
649  upgrade to stronger hash algorithms as they become available */
650  status = krnlSendMessage( iCryptHandle, IMESSAGE_GETATTRIBUTE,
651  &certHashAlgo, CRYPT_IATTRIBUTE_CERTHASHALGO );
652  if( cryptStatusOK( status ) && \
653  isStrongerHash( certHashAlgo, envelopeInfoPtr->defaultHash ) )
654  envelopeInfoPtr->defaultHash = certHashAlgo;
655 
656  /* If there's no subject hash action available, create one so that we
657  can connect it to the signature action */
658  if( envelopeInfoPtr->actionList == NULL )
659  {
660  MESSAGE_CREATEOBJECT_INFO createInfo;
661 
662  /* Create a default hash action */
663  setMessageCreateObjectInfo( &createInfo, envelopeInfoPtr->defaultHash );
665  IMESSAGE_DEV_CREATEOBJECT, &createInfo,
667  if( cryptStatusError( status ) )
668  return( status );
669 
670  /* Add the hash action to the list */
671  status = addActionEx( &hashActionPtr, &envelopeInfoPtr->actionList,
672  envelopeInfoPtr->memPoolState, ACTION_HASH,
673  createInfo.cryptHandle );
674  if( cryptStatusError( status ) )
675  {
677  return( status );
678  }
679 
680  /* Remember that the action was added invisibly to the caller so that
681  we don't return an error if they add it explicitly later on, and
682  that it needs to be attached to a controlling action before it
683  can be used */
684  hashActionPtr->flags |= ACTION_ADDEDAUTOMATICALLY | \
685  ACTION_NEEDSCONTROLLER;
686  }
687  else
688  {
689  /* Find the last hash action that was added */
690  hashActionPtr = findLastAction( envelopeInfoPtr->actionList,
691  ACTION_HASH );
692  if( hashActionPtr == NULL )
693  {
694  setErrorInfo( envelopeInfoPtr, CRYPT_ENVINFO_HASH,
696  return( CRYPT_ERROR_NOTINITED );
697  }
698  }
699 
700  /* Connect the signature action to the last hash action that was added
701  and remember that this action now has a controlling action */
702  actionListPtr->associatedAction = hashActionPtr;
703  hashActionPtr->flags &= ~ACTION_NEEDSCONTROLLER;
704 
705  return( CRYPT_OK );
706  }
707 
708 /****************************************************************************
709 * *
710 * Enveloping Information Management Functions *
711 * *
712 ****************************************************************************/
713 
714 /* Add enveloping information to an envelope */
715 
717 static int addEnvelopeInfo( INOUT ENVELOPE_INFO *envelopeInfoPtr,
718  IN_ATTRIBUTE const CRYPT_ATTRIBUTE_TYPE envInfo,
719  IN_INT_Z const int value )
720  {
721  CRYPT_HANDLE cryptHandle = ( CRYPT_HANDLE ) value;
723 
724  assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
725 
726  REQUIRES( ( envInfo == CRYPT_IATTRIBUTE_INCLUDESIGCERT ) || \
727  ( envInfo == CRYPT_IATTRIBUTE_ATTRONLY ) || \
728  ( envInfo > CRYPT_ENVINFO_FIRST && \
729  envInfo < CRYPT_ENVINFO_LAST ) );
730 
731  /* If it's a generic "add a context" action for a PGP envelope check
732  that everything is valid. This is necessary because the PGP format
733  doesn't support the full range of enveloping capabilities */
734 #ifdef USE_PGP
735  if( envelopeInfoPtr->type == CRYPT_FORMAT_PGP && \
736  envInfo > CRYPT_ENVINFO_FIRST && \
737  envInfo < CRYPT_ENVINFO_LAST )
738  {
739  const int status = checkPgpUsage( envelopeInfoPtr, envInfo );
740  if( cryptStatusError( status ) )
741  {
742  setErrorInfo( envelopeInfoPtr, envInfo,
744  return( status );
745  }
746  }
747 #endif /* USE_PGP */
748 
749  /* If it's meta-information, remember the value */
750  switch( envInfo )
751  {
752  case CRYPT_IATTRIBUTE_INCLUDESIGCERT:
753  /* This is on by default so we should only be turning it off */
754  REQUIRES( value == FALSE );
755 
756  envelopeInfoPtr->flags |= ENVELOPE_NOSIGNINGCERTS;
757  return( CRYPT_OK );
758 
759  case CRYPT_IATTRIBUTE_ATTRONLY:
760  /* This is off by default so we should only be turning it on */
761  REQUIRES( value == TRUE );
762 
763  /* Detached-signature and attribute-only messages are mutually
764  exclusive */
765  if( envelopeInfoPtr->flags & ENVELOPE_DETACHED_SIG )
766  {
769  return( CRYPT_ERROR_INITED );
770  }
771  envelopeInfoPtr->flags |= ENVELOPE_ATTRONLY;
772  return( CRYPT_OK );
773 
775  envelopeInfoPtr->payloadSize = value;
776  return( CRYPT_OK );
777 
779  envelopeInfoPtr->contentType = value;
780  return( CRYPT_OK );
781 
783  if( value )
784  {
785  /* Detached-signature and attribute-only messages are
786  mutually exclusive. Since the attribute-only message
787  attribute is internal we can't set extended error
788  information for this one */
789  if( envelopeInfoPtr->flags & ENVELOPE_ATTRONLY )
790  return( CRYPT_ERROR_INITED );
791  envelopeInfoPtr->flags |= ENVELOPE_DETACHED_SIG;
792  }
793  else
794  envelopeInfoPtr->flags &= ~ENVELOPE_DETACHED_SIG;
795  return( CRYPT_OK );
796 
798  switch( value )
799  {
801  return( CRYPT_OK );
802 
804  envelopeInfoPtr->usage = ACTION_MAC;
805  return( CRYPT_OK );
806 
808  /* If we're using authenticated encryption in the form
809  of crypt + MAC (rather than a combined auth-enc
810  encryption mode) then we can't use a raw session key
811  because there are effectively two keys present, one
812  for the encryption and one for the MACing. We
813  generalise the check here to make sure that there are
814  no main envelope actions set, in practice this can't
815  happen because setting e.g. a hash action will set
816  the envelope usage to USAGE_SIGN which precludes then
817  setting CRYPT_ENVINFO_INTEGRITY, but the more general
818  check here can't hurt */
819  if( envelopeInfoPtr->actionList != NULL )
820  {
821  setErrorInfo( envelopeInfoPtr,
824  return( CRYPT_ERROR_INITED );
825  }
826 
827  envelopeInfoPtr->usage = ACTION_CRYPT;
828  envelopeInfoPtr->flags |= ENVELOPE_AUTHENC;
829  return( CRYPT_OK );
830  }
831  retIntError();
832 
836  /* It's keyset information, just keep a record of it for later
837  use */
838  return( addKeysetInfo( envelopeInfoPtr, envInfo, cryptHandle ) );
839 
842  {
843  CRYPT_HANDLE *iCryptHandlePtr;
844 
845  /* Find the last signature action that was added and make sure
846  that it doesn't already have an action of this type attached
847  to it */
848  actionListPtr = findLastAction( envelopeInfoPtr->postActionList,
849  ACTION_SIGN );
850  if( actionListPtr == NULL )
851  {
852  setErrorInfo( envelopeInfoPtr, CRYPT_ENVINFO_SIGNATURE,
854  return( CRYPT_ERROR_NOTINITED );
855  }
856  iCryptHandlePtr = ( envInfo == CRYPT_ENVINFO_SIGNATURE_EXTRADATA ) ? \
857  &actionListPtr->iExtraData : \
858  &actionListPtr->iTspSession;
859  if( *iCryptHandlePtr != CRYPT_ERROR )
860  {
861  setErrorInfo( envelopeInfoPtr, envInfo,
863  return( CRYPT_ERROR_INITED );
864  }
865 
866  /* Increment its reference count and add it to the action */
867  krnlSendNotifier( cryptHandle, IMESSAGE_INCREFCOUNT );
868  *iCryptHandlePtr = cryptHandle;
869  return( CRYPT_OK );
870  }
871 
873  /* Historic value only needed for Fortezza */
874  return( CRYPT_ARGERROR_NUM1 );
875 
877 #ifdef USE_COMPRESSION
878  /* Make sure that we don't try and initialise the compression
879  multiple times */
880  if( envelopeInfoPtr->flags & ENVELOPE_ZSTREAMINITED )
881  {
882  setErrorInfo( envelopeInfoPtr, CRYPT_ENVINFO_COMPRESSION,
884  return( CRYPT_ERROR_INITED );
885  }
886 
887  /* Initialize the compression */
888  if( deflateInit( &envelopeInfoPtr->zStream, \
890  return( CRYPT_ERROR_MEMORY );
891  envelopeInfoPtr->flags |= ENVELOPE_ZSTREAMINITED;
892 
893  return( CRYPT_OK );
894 #else
895  return( CRYPT_ARGERROR_NUM1 );
896 #endif /* USE_COMPRESSION */
897 
900  return( addContextInfo( envelopeInfoPtr, cryptHandle,
901  &envelopeInfoPtr->preActionList,
903 
904  case CRYPT_ENVINFO_KEY:
905  /* PGP doesn't allow KEK-based encryption so if it's a PGP
906  envelope we drop through and treat it as a session key */
907  if( envelopeInfoPtr->type != CRYPT_FORMAT_PGP )
908  {
909  return( addContextInfo( envelopeInfoPtr, cryptHandle,
910  &envelopeInfoPtr->preActionList,
911  ACTION_KEYEXCHANGE ) );
912  }
913  /* Fall through */
914 
916  /* We can't add more than one session key */
917  if( envelopeInfoPtr->actionList != NULL )
918  {
919  setErrorInfo( envelopeInfoPtr, CRYPT_ENVINFO_SESSIONKEY,
921  return( CRYPT_ERROR_INITED );
922  }
923 
924  /* If we're using authenticated encryption in the form of crypt +
925  MAC (rather than a combined auth-enc encryption mode) then we
926  can't use a raw session key because there are effectively two
927  keys present, one for the encryption and one for the MACing */
928  if( envelopeInfoPtr->flags & ENVELOPE_AUTHENC )
929  {
930  setErrorInfo( envelopeInfoPtr, CRYPT_ENVINFO_INTEGRITY,
932  return( CRYPT_ERROR_INITED );
933  }
934 
935  return( addContextInfo( envelopeInfoPtr, cryptHandle,
936  &envelopeInfoPtr->actionList,
937  ACTION_CRYPT ) );
938 
939  case CRYPT_ENVINFO_HASH:
940  return( addContextInfo( envelopeInfoPtr, cryptHandle,
941  &envelopeInfoPtr->actionList,
942  ACTION_HASH ) );
943 
945  return( addContextInfo( envelopeInfoPtr, cryptHandle,
946  &envelopeInfoPtr->postActionList,
947  ACTION_SIGN ) );
948  }
949 
950  retIntError();
951  }
952 
954 static int addEnvelopeInfoString( INOUT ENVELOPE_INFO *envelopeInfoPtr,
957  const CRYPT_ATTRIBUTE_TYPE envInfo,
958  IN_BUFFER( valueLength ) const void *value,
960  const int valueLength )
961  {
962  assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
963  assert( isReadPtr( value, valueLength ) );
964 
965  REQUIRES( envInfo == CRYPT_ENVINFO_PASSWORD );
966  REQUIRES( valueLength > 0 && valueLength <= CRYPT_MAX_TEXTSIZE );
967 
968 #ifdef USE_PGP
969  if( envelopeInfoPtr->type == CRYPT_FORMAT_PGP )
970  return( addPgpPasswordInfo( envelopeInfoPtr, value, valueLength ) );
971 #endif /* USE_PGP */
972  return( addPasswordInfo( envelopeInfoPtr, value, valueLength ) );
973  }
974 
975 /****************************************************************************
976 * *
977 * Envelope Access Routines *
978 * *
979 ****************************************************************************/
980 
981 STDC_NONNULL_ARG( ( 1 ) ) \
982 void initEnvResourceHandling( INOUT ENVELOPE_INFO *envelopeInfoPtr )
983  {
984  assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
985 
986  REQUIRES_V( !( envelopeInfoPtr->flags & ENVELOPE_ISDEENVELOPE ) );
987 
988  /* Set the access method pointers */
989  envelopeInfoPtr->addInfo = addEnvelopeInfo;
990  envelopeInfoPtr->addInfoString = addEnvelopeInfoString;
991  envelopeInfoPtr->checkMissingInfo = checkMissingInfo;
992  }
993 #endif /* USE_ENVELOPES */