cryptlib  3.4.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros
pgp_env.c
Go to the documentation of this file.
1 /****************************************************************************
2 * *
3 * cryptlib PGP Enveloping Routines *
4 * Copyright Peter Gutmann 1996-2008 *
5 * *
6 ****************************************************************************/
7 
8 #if defined( INC_ALL )
9  #include "pgp_rw.h"
10  #include "envelope.h"
11 #else
12  #include "enc_dec/pgp_rw.h"
13  #include "envelope/envelope.h"
14 #endif /* Compiler-specific includes */
15 
16 #ifdef USE_PGP
17 
18 /****************************************************************************
19 * *
20 * Utility Routines *
21 * *
22 ****************************************************************************/
23 
24 /* Sanity-check the envelope state */
25 
27 static BOOLEAN sanityCheck( const ENVELOPE_INFO *envelopeInfoPtr )
28  {
29  assert( isReadPtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
30 
31  /* Make sure that general envelope state is in order */
32  if( envelopeInfoPtr->flags & ENVELOPE_ISDEENVELOPE )
33  return( FALSE );
34  if( envelopeInfoPtr->envState < ENVSTATE_NONE || \
35  envelopeInfoPtr->envState >= ENVSTATE_LAST )
36  return( FALSE );
37 
38  /* Make sure that the buffer position is within bounds */
39  if( envelopeInfoPtr->buffer == NULL || \
40  envelopeInfoPtr->bufPos < 0 || \
41  envelopeInfoPtr->bufPos > envelopeInfoPtr->bufSize || \
42  envelopeInfoPtr->bufSize < MIN_BUFFER_SIZE || \
43  envelopeInfoPtr->bufSize >= MAX_INTLENGTH )
44  return( FALSE );
45 
46  /* If the auxBuffer isn't being used, make sure that all values related
47  to it are clear */
48  if( envelopeInfoPtr->auxBuffer != NULL || \
49  envelopeInfoPtr->auxBufPos != 0 || envelopeInfoPtr->auxBufSize != 0 )
50  return( FALSE );
51 
52  return( TRUE );
53  }
54 
55 /* Check that a requested algorithm type is valid with PGP data */
56 
57 CHECK_RETVAL_BOOL \
60  {
61  int dummy;
62 
63  REQUIRES_B( cryptAlgo > CRYPT_ALGO_NONE && \
64  cryptAlgo < CRYPT_ALGO_LAST_EXTERNAL );
65  REQUIRES_B( ( cryptMode == CRYPT_MODE_NONE ) || \
66  ( cryptMode > CRYPT_MODE_NONE && \
67  cryptMode < CRYPT_MODE_LAST ) );
68 
69  if( cryptStatusError( cryptlibToPgpAlgo( cryptAlgo, &dummy ) ) )
70  return( FALSE );
71  if( isConvAlgo( cryptAlgo ) )
72  {
73  if( cryptMode != CRYPT_MODE_CFB )
74  return( FALSE );
75  }
76  else
77  {
78  if( cryptMode != CRYPT_MODE_NONE )
79  return( FALSE );
80  }
81 
82  return( TRUE );
83  }
84 
85 /****************************************************************************
86 * *
87 * Write Key Exchange/Signature Packets *
88 * *
89 ****************************************************************************/
90 
91 /* One-pass signature info:
92 
93  byte version = 3
94  byte sigType
95  byte hashAlgo
96  byte sigAlgo
97  byte[8] keyID
98  byte 1
99 
100  This is additional header data written at the start of a block of signed
101  data rather than a standard PGP packet so we can't write it using the
102  normal PGP packet read/write routines */
103 
105 static int writeSignatureInfoPacket( INOUT STREAM *stream,
108  {
109  BYTE keyID[ PGP_KEYID_SIZE + 8 ];
110  int hashAlgo, signAlgo = DUMMY_INIT; /* int vs.enum */
111  int pgpHashAlgo, pgpCryptAlgo = DUMMY_INIT, status;
112 
113  assert( isWritePtr( stream, sizeof( STREAM ) ) );
114 
115  REQUIRES( isHandleRangeValid( iSignContext ) );
116  REQUIRES( isHandleRangeValid( iHashContext ) );
117 
118  /* Get the signature information */
119  status = krnlSendMessage( iHashContext, IMESSAGE_GETATTRIBUTE,
120  &hashAlgo, CRYPT_CTXINFO_ALGO );
121  if( cryptStatusOK( status ) )
122  status = krnlSendMessage( iSignContext, IMESSAGE_GETATTRIBUTE,
123  &signAlgo, CRYPT_CTXINFO_ALGO );
124  if( cryptStatusOK( status ) )
125  {
127 
128  setMessageData( &msgData, keyID, PGP_KEYID_SIZE );
129  status = krnlSendMessage( iSignContext, IMESSAGE_GETATTRIBUTE_S,
130  &msgData, CRYPT_IATTRIBUTE_KEYID_OPENPGP );
131  }
132  if( cryptStatusError( status ) )
133  return( status );
134  status = cryptlibToPgpAlgo( hashAlgo, &pgpHashAlgo );
135  if( cryptStatusOK( status ) )
136  status = cryptlibToPgpAlgo( signAlgo, &pgpCryptAlgo );
137  ENSURES( cryptStatusOK( status ) );
138 
139  /* Write the signature info packet. Note that the version 3 value is
140  normally used to identify a legal-kludged PGP 2.0 but in this case it
141  denotes OpenPGP, which usually has the version 4 value rather than 3 */
142  pgpWritePacketHeader( stream, PGP_PACKET_SIGNATURE_ONEPASS, \
145  sputc( stream, 3 ); /* Version = 3 (OpenPGP) */
146  sputc( stream, 0 ); /* Binary document signature */
147  sputc( stream, pgpHashAlgo );
148  sputc( stream, pgpCryptAlgo );
149  swrite( stream, keyID, PGP_KEYID_SIZE );
150  return( sputc( stream, 1 ) );
151  }
152 
153 /****************************************************************************
154 * *
155 * Write Header Packets *
156 * *
157 ****************************************************************************/
158 
159 /* Write the data header packet */
160 
162 static int writeHeaderPacket( INOUT ENVELOPE_INFO *envelopeInfoPtr )
163  {
164  STREAM stream;
165  int status = CRYPT_OK;
166 
167  assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
168 
169  /* If we're encrypting, set up the encryption-related information.
170  Since PGP doesn't perform a key exchange of a session key when
171  conventionally-encrypting data the encryption information could be
172  coming from either an encryption action (derived from a password) or
173  a conventional key exchange action that results in the direct
174  creation of a session encryption key */
175  if( envelopeInfoPtr->usage == ACTION_CRYPT )
176  {
177  status = initEnvelopeEncryption( envelopeInfoPtr,
178  envelopeInfoPtr->actionList->iCryptHandle,
179  CRYPT_ALGO_NONE, CRYPT_MODE_NONE, NULL, 0,
180  FALSE );
181  if( cryptStatusError( status ) )
182  return( status );
183 
184  /* Prepare to start emitting the key exchange (PKC-encrypted) or
185  session key (conventionally encrypted) actions */
186  envelopeInfoPtr->lastAction = \
187  findAction( envelopeInfoPtr->preActionList,
189  if( envelopeInfoPtr->lastAction == NULL )
190  {
191  /* There's no key exchange action, we're using a raw session key
192  derived from a password */
193  envelopeInfoPtr->lastAction = envelopeInfoPtr->actionList;
194  }
195  envelopeInfoPtr->envState = ENVSTATE_KEYINFO;
196 
197  ENSURES( envelopeInfoPtr->lastAction != NULL );
198 
199  return( CRYPT_OK );
200  }
201 
202  /* If we're not encrypting data (i.e. there's only a single packet
203  present rather than a packet preceded by a pile of key exchange
204  actions) we write the appropriate PGP header based on the envelope
205  usage */
206  sMemOpen( &stream, envelopeInfoPtr->buffer, envelopeInfoPtr->bufSize );
207  switch( envelopeInfoPtr->usage )
208  {
209  case ACTION_SIGN:
210  if( !( envelopeInfoPtr->flags & ENVELOPE_DETACHED_SIG ) )
211  {
212  status = writeSignatureInfoPacket( &stream,
213  envelopeInfoPtr->postActionList->iCryptHandle,
214  envelopeInfoPtr->actionList->iCryptHandle );
215  if( cryptStatusError( status ) )
216  break;
217  }
218 
219  /* Since we can only sign literal data we need to explicitly
220  write an inner data header */
221  REQUIRES( envelopeInfoPtr->contentType == CRYPT_CONTENT_DATA );
222  envelopeInfoPtr->envState = ENVSTATE_DATA;
223  break;
224 
225  case ACTION_NONE:
226  /* Write the header followed by an indicator that we're using
227  opaque content, a zero-length filename, and no date */
228  pgpWritePacketHeader( &stream, PGP_PACKET_DATA,
229  envelopeInfoPtr->payloadSize + \
231  status = swrite( &stream, PGP_DATA_HEADER, PGP_DATA_HEADER_SIZE );
232  break;
233 
234  case ACTION_COMPRESS:
235  /* Compressed data packets use a special unkown-length encoding
236  that doesn't work like any other PGP packet type so we can't
237  use pgpWritePacketHeader() for this packet type but have to
238  hand-assemble the header ourselves */
239  sputc( &stream, PGP_CTB_COMPRESSED );
240  status = sputc( &stream, PGP_ALGO_ZLIB );
241  if( cryptStatusError( status ) )
242  break;
243  if( envelopeInfoPtr->contentType == CRYPT_CONTENT_DATA )
244  {
245  /* If there's no inner content type we need to explicitly
246  write an inner data header */
247  envelopeInfoPtr->envState = ENVSTATE_DATA;
248  }
249  break;
250 
251  default:
252  retIntError();
253  }
254  if( cryptStatusOK( status ) )
255  envelopeInfoPtr->bufPos = stell( &stream );
256  sMemDisconnect( &stream );
257  if( cryptStatusError( status ) )
258  return( status );
259 
260  /* Reset the segmentation state. Although PGP doesn't segment the
261  payload we still have to reset the state to synchronise things like
262  payload hashing and encryption. We also set the block size mask to
263  all ones if we're not encrypting since we can begin and end data
264  segments on arbitrary boundaries */
265  envelopeInfoPtr->dataFlags |= ENVDATA_SEGMENTCOMPLETE;
266  if( envelopeInfoPtr->usage != ACTION_CRYPT )
267  envelopeInfoPtr->blockSizeMask = -1;
268  envelopeInfoPtr->lastAction = NULL;
269 
270  /* If we're not emitting any inner header, we're done */
271  if( envelopeInfoPtr->envState == ENVSTATE_HEADER || \
272  ( envelopeInfoPtr->flags & ENVELOPE_DETACHED_SIG ) )
273  envelopeInfoPtr->envState = ENVSTATE_DONE;
274 
275  return( CRYPT_OK );
276  }
277 
278 /****************************************************************************
279 * *
280 * Header/Trailer Processing Routines *
281 * *
282 ****************************************************************************/
283 
284 /* Write key exchange actions */
285 
287 static int writeKeyex( INOUT ENVELOPE_INFO *envelopeInfoPtr )
288  {
289  ACTION_LIST *lastActionPtr;
290  int iterationCount, status = CRYPT_OK;
291 
292  assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
293 
294  /* Export the session key using each of the PKC keys, or write the
295  derivation information needed to recreate the session key */
296  for( lastActionPtr = envelopeInfoPtr->lastAction, iterationCount = 0;
297  lastActionPtr != NULL && iterationCount < FAILSAFE_ITERATIONS_MED;
298  lastActionPtr = lastActionPtr->next, iterationCount++ )
299  {
300  void *bufPtr = envelopeInfoPtr->buffer + envelopeInfoPtr->bufPos;
301  const int dataLeft = min( envelopeInfoPtr->bufSize - \
302  envelopeInfoPtr->bufPos,
303  MAX_INTLENGTH_SHORT - 1 );
304  int keyexSize;
305 
306  /* Make sure that there's enough room to emit this key exchange
307  action */
308  if( lastActionPtr->encodedSize + 128 > dataLeft )
309  {
310  status = CRYPT_ERROR_OVERFLOW;
311  break;
312  }
313 
314  /* Emit the key exchange action */
315  if( lastActionPtr->action == ACTION_KEYEXCHANGE_PKC )
316  {
317  status = iCryptExportKey( bufPtr, dataLeft, &keyexSize,
319  envelopeInfoPtr->iCryptContext,
320  lastActionPtr->iCryptHandle );
321  }
322  else
323  {
324  status = iCryptExportKey( bufPtr, dataLeft, &keyexSize,
326  envelopeInfoPtr->iCryptContext );
327  }
328  if( cryptStatusError( status ) )
329  break;
330  envelopeInfoPtr->bufPos += keyexSize;
331  }
332  ENSURES( iterationCount < FAILSAFE_ITERATIONS_MED )
333  envelopeInfoPtr->lastAction = lastActionPtr;
334 
335  return( status );
336  }
337 
339 static int writeEncryptedContentHeader( INOUT ENVELOPE_INFO *envelopeInfoPtr )
340  {
341  STREAM stream;
342  BYTE ivInfoBuffer[ ( CRYPT_MAX_IVSIZE + 2 ) + 8 ];
343  const int dataLeft = min( envelopeInfoPtr->bufSize - \
344  envelopeInfoPtr->bufPos,
345  MAX_INTLENGTH_SHORT - 1 );
346  int ivSize, status;
347 
348  assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
349 
350  /* Get the IV size and make sure that there's enough room to emit the
351  encrypted content header (+8 for slop space) */
352  status = krnlSendMessage( envelopeInfoPtr->iCryptContext,
353  IMESSAGE_GETATTRIBUTE, &ivSize,
355  if( cryptStatusError( status ) )
356  return( status );
357  if( dataLeft < PGP_MAX_HEADER_SIZE + ( ivSize + 2 ) + 8 )
358  return( CRYPT_ERROR_OVERFLOW );
359 
360  /* Set up the PGP IV information */
361  status = pgpProcessIV( envelopeInfoPtr->iCryptContext,
362  ivInfoBuffer, ivSize + 2, ivSize, TRUE, TRUE );
363  if( cryptStatusError( status ) )
364  return( status );
365 
366  /* Write the encrypted content header */
367  sMemOpen( &stream, envelopeInfoPtr->buffer + envelopeInfoPtr->bufPos,
368  dataLeft );
369  pgpWritePacketHeader( &stream, PGP_PACKET_ENCR,
370  ( ivSize + 2 ) + 1 + \
372  envelopeInfoPtr->payloadSize ) + \
374  envelopeInfoPtr->payloadSize );
375  status = swrite( &stream, ivInfoBuffer, ivSize + 2 );
376  if( cryptStatusOK( status ) )
377  envelopeInfoPtr->bufPos += stell( &stream );
378  sMemDisconnect( &stream );
379 
380  return( status );
381  }
382 
383 /****************************************************************************
384 * *
385 * Envelope Pre/Post-processing Functions *
386 * *
387 ****************************************************************************/
388 
389 /* The following functions take care of pre/post-processing of envelope data
390  during the enveloping process */
391 
393 static int createSessionKey( INOUT ENVELOPE_INFO *envelopeInfoPtr )
394  {
396  MESSAGE_CREATEOBJECT_INFO createInfo;
397  static const int mode = CRYPT_MODE_CFB; /* int vs.enum */
398  int status;
399 
400  assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
401 
402  /* Create a default encryption action */
403  setMessageCreateObjectInfo( &createInfo, envelopeInfoPtr->defaultAlgo );
405  &createInfo, OBJECT_TYPE_CONTEXT );
406  if( cryptStatusError( status ) )
407  return( status );
408  iSessionKeyContext = createInfo.cryptHandle;
409  if( envelopeInfoPtr->defaultAlgo == CRYPT_ALGO_BLOWFISH )
410  {
411  static const int keySize = 16;
412 
413  /* If we're using an algorithm with a variable-length key, restrict
414  it to a fixed length. There shouldn't be any need for this
415  because the key length is communicated as part of the wrapped
416  key, but some implementations choke if it's not exactly 128 bits */
417  status = krnlSendMessage( iSessionKeyContext, IMESSAGE_SETATTRIBUTE,
418  ( MESSAGE_CAST ) &keySize,
420  if( cryptStatusError( status ) )
421  {
422  krnlSendNotifier( iSessionKeyContext, IMESSAGE_DECREFCOUNT );
423  return( status );
424  }
425  }
426  status = krnlSendMessage( iSessionKeyContext, IMESSAGE_SETATTRIBUTE,
427  ( MESSAGE_CAST ) &mode, CRYPT_CTXINFO_MODE );
428  if( cryptStatusOK( status ) )
429  status = krnlSendNotifier( iSessionKeyContext, IMESSAGE_CTX_GENKEY );
430  if( cryptStatusError( status ) )
431  {
432  krnlSendNotifier( iSessionKeyContext, IMESSAGE_DECREFCOUNT );
433  return( status );
434  }
435 
436  /* Add the session-key action to the action list */
437  status = addAction( &envelopeInfoPtr->actionList,
438  envelopeInfoPtr->memPoolState, ACTION_CRYPT,
439  iSessionKeyContext );
440  if( cryptStatusError( status ) )
441  {
442  krnlSendNotifier( iSessionKeyContext, IMESSAGE_DECREFCOUNT );
443  return( status );
444  }
445 
446  return( CRYPT_OK );
447  }
448 
450 static int preEnvelopeEncrypt( INOUT ENVELOPE_INFO *envelopeInfoPtr )
451  {
452  CRYPT_DEVICE iCryptDevice = CRYPT_ERROR;
454  int iterationCount, status;
455 
456  assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
457 
458  REQUIRES( envelopeInfoPtr->usage == ACTION_CRYPT );
459  REQUIRES( findAction( envelopeInfoPtr->preActionList, \
460  ACTION_KEYEXCHANGE_PKC ) != NULL );
461 
462  /* Create the session key if necessary */
463  if( envelopeInfoPtr->actionList == NULL )
464  {
465  status = createSessionKey( envelopeInfoPtr );
466  if( cryptStatusError( status ) )
467  return( status );
468  }
469  else
470  {
471  /* If the session key context is tied to a device, get its handle so
472  we can check that all key exchange objects are also in the same
473  device */
474  status = krnlSendMessage( envelopeInfoPtr->actionList->iCryptHandle,
475  MESSAGE_GETDEPENDENT, &iCryptDevice,
477  if( cryptStatusError( status ) )
478  iCryptDevice = CRYPT_ERROR;
479  }
480 
481  /* Notify the kernel that the session key context is attached to the
482  envelope. This is an internal object used only by the envelope so we
483  tell the kernel not to increment its reference count when it attaches
484  it */
485  status = krnlSendMessage( envelopeInfoPtr->objectHandle,
487  &envelopeInfoPtr->actionList->iCryptHandle,
489  if( cryptStatusError( status ) )
490  return( status );
491 
492  /* Now walk down the list of key exchange actions connecting each one to
493  the session key action. The caller has already guaranteed that there's
494  at least one PKC keyex action present */
495  for( actionListPtr = findAction( envelopeInfoPtr->preActionList,
497  iterationCount = 0;
498  actionListPtr != NULL && \
499  actionListPtr->action == ACTION_KEYEXCHANGE_PKC && \
500  iterationCount < FAILSAFE_ITERATIONS_MED;
501  actionListPtr = actionListPtr->next, iterationCount++ )
502  {
503  /* If the session key context is tied to a device, make sure that
504  the key exchange object is in the same device */
505  if( iCryptDevice != CRYPT_ERROR )
506  {
507  CRYPT_DEVICE iKeyexDevice;
508 
509  status = krnlSendMessage( actionListPtr->iCryptHandle,
510  MESSAGE_GETDEPENDENT, &iKeyexDevice,
512  if( cryptStatusError( status ) || iCryptDevice != iKeyexDevice )
513  return( CRYPT_ERROR_INVALID );
514  }
515 
516  /* Remember that we now have a controlling action and connect the
517  controller to the subject */
518  envelopeInfoPtr->actionList->flags &= ~ACTION_NEEDSCONTROLLER;
519  actionListPtr->associatedAction = envelopeInfoPtr->actionList;
520 
521  /* Evaluate the size of the exported action. We only get PKC
522  actions at this point so we don't have to provide any special-
523  case handling for other key exchange types */
524  status = iCryptExportKey( NULL, 0, &actionListPtr->encodedSize,
526  envelopeInfoPtr->actionList->iCryptHandle,
527  actionListPtr->iCryptHandle );
528  if( cryptStatusError( status ) )
529  return( status );
530  }
531  ENSURES( iterationCount < FAILSAFE_ITERATIONS_MED );
532 
533  return( CRYPT_OK );
534  }
535 
537 static int preEnvelopeSign( const ENVELOPE_INFO *envelopeInfoPtr )
538  {
539  ACTION_LIST *actionListPtr = envelopeInfoPtr->postActionList;
541 
542  assert( isReadPtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
543 
544  REQUIRES( envelopeInfoPtr->usage == ACTION_SIGN );
545 
546  /* Make sure that there's at least one signing action present */
547  if( actionListPtr == NULL )
548  return( CRYPT_ERROR_NOTINITED );
549 
550  assert( isWritePtr( actionListPtr, sizeof( ACTION_LIST ) ) );
551 
552  REQUIRES( actionListPtr->associatedAction != NULL );
553 
554  /* Evaluate the size of the signature action */
555  initSigParams( &sigParams );
556  sigParams.sigType = PGP_SIG_DATA;
557  return( iCryptCreateSignature( NULL, 0, &actionListPtr->encodedSize,
558  CRYPT_FORMAT_PGP, actionListPtr->iCryptHandle,
559  actionListPtr->associatedAction->iCryptHandle,
560  &sigParams ) );
561  }
562 
563 /****************************************************************************
564 * *
565 * Emit Envelope Preamble/Postamble *
566 * *
567 ****************************************************************************/
568 
569 /* Output as much of the preamble as possible into the envelope buffer */
570 
572 static int emitPreamble( INOUT ENVELOPE_INFO *envelopeInfoPtr )
573  {
574  int status = CRYPT_OK;
575 
576  assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
577 
578  REQUIRES( sanityCheck( envelopeInfoPtr ) );
579 
580  /* If we've finished processing the header information, don't do
581  anything */
582  if( envelopeInfoPtr->envState == ENVSTATE_DONE )
583  return( CRYPT_OK );
584 
585  /* If we haven't started doing anything yet, perform various final
586  initialisations */
587  if( envelopeInfoPtr->envState == ENVSTATE_NONE )
588  {
589  /* If there's no nested content type set, default to plain data */
590  if( envelopeInfoPtr->contentType == CRYPT_CONTENT_NONE )
591  envelopeInfoPtr->contentType = CRYPT_CONTENT_DATA;
592 
593  /* If there's an absolute data length set, remember it for when we
594  copy in data */
595  if( envelopeInfoPtr->payloadSize != CRYPT_UNUSED )
596  envelopeInfoPtr->segmentSize = envelopeInfoPtr->payloadSize;
597 
598  /* Perform any remaining initialisation. Since PGP derives the
599  session key directly from the user password we only perform the
600  encryption initialisation if there are PKC key exchange actions
601  present */
602  if( envelopeInfoPtr->usage == ACTION_CRYPT && \
603  findAction( envelopeInfoPtr->preActionList,
604  ACTION_KEYEXCHANGE_PKC ) != NULL )
605  status = preEnvelopeEncrypt( envelopeInfoPtr );
606  else
607  {
608  if( envelopeInfoPtr->usage == ACTION_SIGN )
609  status = preEnvelopeSign( envelopeInfoPtr );
610  }
611  if( cryptStatusError( status ) )
612  {
613  retExt( status,
614  ( status, ENVELOPE_ERRINFO,
615  "Couldn't perform final %s initialisation prior to "
616  "enveloping data",
617  ( envelopeInfoPtr->usage == ACTION_SIGN ) ? \
618  "signing" : "encryption" ) );
619  }
620 
621  /* Delete any orphaned actions such as automatically-added hash
622  actions that were overridden with user-supplied alternate
623  actions */
624  status = deleteUnusedActions( envelopeInfoPtr );
625  if( cryptStatusError( status ) )
626  return( status );
627 
628  /* We're ready to go, prepare to emit the outer header */
629  envelopeInfoPtr->envState = ENVSTATE_HEADER;
630 
631  ENSURES( checkActions( envelopeInfoPtr ) );
632  }
633 
634  /* Emit the outer header. This always follows directly from the final
635  initialisation step but we keep the two logically distinct to
636  emphasise the fact that the former is merely finalised enveloping
637  actions without performing any header processing while the latter is
638  the first stage that actually emits header data */
639  if( envelopeInfoPtr->envState == ENVSTATE_HEADER )
640  {
641  status = writeHeaderPacket( envelopeInfoPtr );
642  if( cryptStatusError( status ) )
643  {
644  retExt( status,
645  ( status, ENVELOPE_ERRINFO,
646  "Couldn't create envelope header" ) );
647  }
648  }
649 
650  /* Handle key export actions */
651  if( envelopeInfoPtr->envState == ENVSTATE_KEYINFO )
652  {
653  status = writeKeyex( envelopeInfoPtr );
654  if( cryptStatusError( status ) )
655  {
656  retExt( status,
657  ( status, ENVELOPE_ERRINFO,
658  "Couldn't emit key exchange actions to envelope "
659  "header" ) );
660  }
661 
662  /* Move on to the next state */
663  envelopeInfoPtr->envState = ENVSTATE_ENCRINFO;
664  }
665 
666  /* Handle encrypted content information */
667  if( envelopeInfoPtr->envState == ENVSTATE_ENCRINFO )
668  {
669  /* Write the encrypted content header */
670  status = writeEncryptedContentHeader( envelopeInfoPtr );
671  if( cryptStatusError( status ) )
672  {
673  retExt( status,
674  ( status, ENVELOPE_ERRINFO,
675  "Couldn't emit encrypted content header to envelope "
676  "header" ) );
677  }
678 
679  /* Make sure that we start a new segment if we try to add any data */
680  envelopeInfoPtr->dataFlags |= ENVDATA_SEGMENTCOMPLETE;
681 
682  /* Before we can finish we have to push in the inner data header */
683  envelopeInfoPtr->envState = ENVSTATE_DATA;
684  }
685 
686  /* Handle data payload information */
687  if( envelopeInfoPtr->envState == ENVSTATE_DATA )
688  {
689  STREAM stream;
690  BYTE headerBuffer[ 64 + 8 ];
691 
692  /* Make sure that there's enough room to emit the data header (+8
693  for slop space) */
694  if( envelopeInfoPtr->bufPos + PGP_MAX_HEADER_SIZE + \
695  PGP_DATA_HEADER_SIZE + 8 >= envelopeInfoPtr->bufSize )
696  return( CRYPT_ERROR_OVERFLOW );
697 
698  /* Write the payload header. Since this may be encrypted we have to
699  do it indirectly via copyToEnvelope() */
700  sMemOpen( &stream, headerBuffer, 64 );
701  pgpWritePacketHeader( &stream, PGP_PACKET_DATA,
702  PGP_DATA_HEADER_SIZE + envelopeInfoPtr->payloadSize );
703  status = swrite( &stream, PGP_DATA_HEADER, PGP_DATA_HEADER_SIZE );
704  if( cryptStatusOK( status ) && \
705  envelopeInfoPtr->payloadSize != CRYPT_UNUSED )
706  {
707  /* There's an absolute data length set, adjust the running total
708  count by the size of the additional header that's been
709  prepended */
710  envelopeInfoPtr->segmentSize += stell( &stream );
711  }
712  if( cryptStatusOK( status ) )
713  status = envelopeInfoPtr->copyToEnvelopeFunction( envelopeInfoPtr,
714  headerBuffer, stell( &stream ) );
715  sMemClose( &stream );
716  if( cryptStatusError( status ) )
717  {
718  retExt( status,
719  ( status, ENVELOPE_ERRINFO,
720  "Couldn't emit data header into envelope header" ) );
721  }
722 
723  /* We've processed the header, if this is signed data we start
724  hashing from this point. The PGP RFCs are wrong in this regard
725  in that only the payload is hashed and not the entire packet */
726  if( envelopeInfoPtr->usage == ACTION_SIGN )
727  envelopeInfoPtr->dataFlags |= ENVDATA_HASHACTIONSACTIVE;
728 
729  /* We're finished */
730  envelopeInfoPtr->envState = ENVSTATE_DONE;
731  }
732 
733  ENSURES( sanityCheck( envelopeInfoPtr ) );
734 
735  return( CRYPT_OK );
736  }
737 
738 /* Output as much of the postamble as possible into the envelope buffer */
739 
741 static int emitPostamble( INOUT ENVELOPE_INFO *envelopeInfoPtr,
742  STDC_UNUSED const BOOLEAN dummy )
743  {
745  int sigBufSize, sigSize, status;
746 
747  assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
748 
749  REQUIRES( sanityCheck( envelopeInfoPtr ) );
750 
751  /* Before we can emit the trailer we need to flush any remaining data
752  from internal buffers */
753  if( envelopeInfoPtr->envState == ENVSTATE_NONE )
754  {
755  status = envelopeInfoPtr->copyToEnvelopeFunction( envelopeInfoPtr,
756  NULL, 0 );
757  if( cryptStatusError( status ) )
758  {
759  retExt( status,
760  ( status, ENVELOPE_ERRINFO,
761  "Couldn't flush remaining data into envelope "
762  "buffer" ) );
763  }
764  envelopeInfoPtr->envState = ENVSTATE_FLUSHED;
765  }
766 
767  /* The only PGP packet that has a trailer is signed data using the new
768  (post-2.x) one-pass signature packet, if we're not signing data we can
769  exit now */
770  if( envelopeInfoPtr->usage != ACTION_SIGN )
771  {
772  /* We're done */
773  envelopeInfoPtr->envState = ENVSTATE_DONE;
774 
775  ENSURES( sanityCheck( envelopeInfoPtr ) );
776 
777  return( CRYPT_OK );
778  }
779 
780  /* Check whether there's enough room left in the buffer to emit the
781  signature directly into it. Since signatures are fairly small (a few
782  hundred bytes) we always require enough room in the buffer and don't
783  bother with any overflow handling via the auxBuffer */
784  sigBufSize = min( envelopeInfoPtr->bufSize - envelopeInfoPtr->bufPos,
785  MAX_INTLENGTH_SHORT - 1 );
786  if( envelopeInfoPtr->postActionList->encodedSize + 64 > sigBufSize )
787  return( CRYPT_ERROR_OVERFLOW );
788 
789  /* Sign the data */
790  initSigParams( &sigParams );
791  sigParams.sigType = PGP_SIG_DATA;
792  status = iCryptCreateSignature( envelopeInfoPtr->buffer + \
793  envelopeInfoPtr->bufPos, sigBufSize, &sigSize,
795  envelopeInfoPtr->postActionList->iCryptHandle,
796  envelopeInfoPtr->actionList->iCryptHandle, &sigParams );
797  if( cryptStatusError( status ) )
798  {
799  retExt( status,
800  ( status, ENVELOPE_ERRINFO,
801  "Couldn't emit signature to envelope trailer" ) );
802  }
803  envelopeInfoPtr->bufPos += sigSize;
804 
805  /* Now that we've written the final data, set the end-of-segment-data
806  pointer to the end of the data in the buffer so that
807  copyFromEnvelope() can copy out the remaining data */
808  envelopeInfoPtr->segmentDataEnd = envelopeInfoPtr->bufPos;
809  envelopeInfoPtr->envState = ENVSTATE_DONE;
810 
811  ENSURES( sanityCheck( envelopeInfoPtr ) );
812 
813  return( CRYPT_OK );
814  }
815 
816 /****************************************************************************
817 * *
818 * Envelope Access Routines *
819 * *
820 ****************************************************************************/
821 
822 STDC_NONNULL_ARG( ( 1 ) ) \
823 void initPGPEnveloping( INOUT ENVELOPE_INFO *envelopeInfoPtr )
824  {
825  int algorithm, dummy, status;
826 
827  assert( isWritePtr( envelopeInfoPtr, sizeof( ENVELOPE_INFO ) ) );
828 
829  REQUIRES_V( !( envelopeInfoPtr->flags & ENVELOPE_ISDEENVELOPE ) );
830 
831  /* Set the access method pointers */
832  envelopeInfoPtr->processPreambleFunction = emitPreamble;
833  envelopeInfoPtr->processPostambleFunction = emitPostamble;
834  envelopeInfoPtr->checkAlgo = pgpCheckAlgo;
835 
836  /* Set up the processing state information */
837  envelopeInfoPtr->envState = ENVSTATE_NONE;
838 
839  /* Remember the current default settings for use with the envelope.
840  Since the PGP algorithms represent only a subset of what's available
841  we have to drop back to fixed values if the caller has selected
842  something exotic */
843  status = krnlSendMessage( envelopeInfoPtr->ownerHandle,
844  IMESSAGE_GETATTRIBUTE, &algorithm,
846  if( cryptStatusError( status ) || \
847  cryptStatusError( cryptlibToPgpAlgo( algorithm, &dummy ) ) )
848  envelopeInfoPtr->defaultHash = CRYPT_ALGO_SHA1;
849  else
850  envelopeInfoPtr->defaultHash = algorithm; /* int vs.enum */
851  status = krnlSendMessage( envelopeInfoPtr->ownerHandle,
852  IMESSAGE_GETATTRIBUTE, &algorithm,
854  if( cryptStatusError( status ) || \
855  cryptStatusError( cryptlibToPgpAlgo( algorithm, &dummy ) ) )
856  envelopeInfoPtr->defaultAlgo = CRYPT_ALGO_3DES;
857  else
858  envelopeInfoPtr->defaultAlgo = algorithm; /* int vs.enum */
859  envelopeInfoPtr->defaultMAC = CRYPT_ALGO_NONE;
860 
861  /* Turn off segmentation of the envelope payload. PGP has a single
862  length at the start of the data and doesn't segment the payload */
863  envelopeInfoPtr->dataFlags |= ENVDATA_NOSEGMENT;
864  }
865 #endif /* USE_PGP */