cryptlib  3.4.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros
envelope.c
Go to the documentation of this file.
1 /****************************************************************************
2 * *
3 * cryptlib Enveloping Test Routines *
4 * Copyright Peter Gutmann 1996-2009 *
5 * *
6 ****************************************************************************/
7 
8 #include <limits.h> /* To determine max.buffer size we can encrypt */
9 #include "cryptlib.h"
10 #include "test/test.h"
11 
12 #if defined( __MVS__ ) || defined( __VMCMS__ )
13  /* Suspend conversion of literals to ASCII. */
14  #pragma convlit( suspend )
15 #endif /* IBM big iron */
16 #if defined( __ILEC400__ )
17  #pragma convert( 0 )
18 #endif /* IBM medium iron */
19 
20 /* Test data to use for the self-test. The PGP test data is slightly
21  different since it's not possible to include a null character in data
22  generated via the command-line versions of PGP. On EBCDIC systems we
23  have to hardcode in the character codes since the pre-generated data
24  came from an ASCII system */
25 
26 #if defined( __MVS__ ) || defined( __VMCMS__ )
27  #define ENVELOPE_TESTDATA ( ( BYTE * ) "\x53\x6F\x6D\x65\x20\x74\x65\x73\x74\x20\x64\x61\x74\x61" )
28  #define ENVELOPE_PGP_TESTDATA ( ( BYTE * ) "\x53\x6F\x6D\x65\x20\x74\x65\x73\x74\x20\x64\x61\x74\x61\x2E" )
29  #define ENVELOPE_COMPRESSEDDATA "\x2F\x2A\x20\x54\x68\x69\x73\x20\x69\x73\x20\x61\x20\x6C\x6F\x77\x65\x73\x74\x2D"
30 #else
31  #define ENVELOPE_TESTDATA ( ( BYTE * ) "Some test data" )
32  #define ENVELOPE_PGP_TESTDATA ( ( BYTE * ) "Some test data." )
33  #define ENVELOPE_COMPRESSEDDATA "/* This is a lowest-"
34 #endif /* EBCDIC systems */
35 #define ENVELOPE_TESTDATA_SIZE 15
36 #define ENVELOPE_COMPRESSEDDATA_SIZE 20
37 
38 /* To convert a CMS blob into an S/MIME message, base64 encode it and add
39  the following header:
40 
41  To: <address>
42  Subject: S/MIME test
43  From: <address>
44  MIME-Version: 1.0
45  Content-Type: application/x-pkcs7-mime;smime-type=signed-data;name="smime.p7m"
46  Content-Disposition: attachment;filename="smime.p7m"
47  Content-Transfer-Encoding: base64
48 
49  <base64-encoded data>
50 
51  To allow the inner message to be processed by a mailer, the contents will
52  themselves have to be MIME-formatted:
53 
54  MIME-Version: 1.0
55  Content-Type: text/plain;charset="us-ascii"
56  Content-Transfer-Encoding: 7bit
57 
58  <text> */
59 
60 /* External flags which indicate that the key read/update routines worked OK.
61  This is set by earlier self-test code, if it isn't set some of the tests
62  are disabled */
63 
64 extern int keyReadOK, doubleCertOK;
65 
66 #if defined( TEST_ENVELOPE ) || defined( TEST_SESSION ) /* For TSP enveloping */
67 
68 /****************************************************************************
69 * *
70 * Utility Routines *
71 * *
72 ****************************************************************************/
73 
74 /* The general-purpose buffer used for enveloping. We use a fixed buffer
75  if possible to save having to add huge amounts of allocation/deallocation
76  code */
77 
78 BYTE FAR_BSS globalBuffer[ BUFFER_SIZE ];
79 
80 /* Determine the size of a file. If there's a problem, we return the
81  default buffer size, which will cause a failure further up the chain
82  where the error can be reported better */
83 
84 static int getFileSize( const char *fileName )
85  {
86  FILE *filePtr;
87  long size;
88 
89  if( ( filePtr = fopen( fileName, "rb" ) ) == NULL )
90  return( BUFFER_SIZE );
91  fseek( filePtr, 0L, SEEK_END );
92  size = ftell( filePtr );
93  fclose( filePtr );
94  if( size > INT_MAX )
95  return( BUFFER_SIZE );
96 
97  return( ( int ) size );
98  }
99 
100 /* Read test data from a file */
101 
102 static int readFileData( const char *fileName, const char *description,
103  BYTE *buffer, const int bufSize )
104  {
105  FILE *filePtr;
106  int count;
107 
108  if( ( filePtr = fopen( fileName, "rb" ) ) == NULL )
109  {
110  printf( "Couldn't find %s file, skipping test of data import...\n",
111  description );
112  return( 0 );
113  }
114  printf( "Testing %s import...\n", description );
115  count = fread( buffer, 1, bufSize, filePtr );
116  fclose( filePtr );
117  if( count >= bufSize )
118  {
119  puts( "The data buffer size is too small for the data. To fix this, "
120  "either increase\nthe BUFFER_SIZE value in " __FILE__ " and "
121  "recompile the code, or use the\ntest code with dynamically-"
122  "allocated buffers." );
123  return( 0 ); /* Skip this test and continue */
124  }
125  if( count < 16 )
126  {
127  printf( "Read failed, only read %d bytes.\n", count );
128  return( 0 ); /* Skip this test and continue */
129  }
130  printf( "%s has size %d bytes.\n", description, count );
131  return( count );
132  }
133 
134 /* Common routines to create an envelope, add enveloping information, push
135  data, pop data, and destroy an envelope */
136 
137 static int createEnvelope( CRYPT_ENVELOPE *envelope,
139  {
140  int status;
141 
142  /* Create the envelope */
143  status = cryptCreateEnvelope( envelope, CRYPT_UNUSED, formatType );
144  if( cryptStatusError( status ) )
145  {
146  printf( "cryptCreateEnvelope() failed with error code %d, line %d.\n",
147  status, __LINE__ );
148  return( FALSE );
149  }
150 
151  return( TRUE );
152  }
153 
154 static int createDeenvelope( CRYPT_ENVELOPE *envelope )
155  {
156  int status;
157 
158  /* Create the envelope */
159  status = cryptCreateEnvelope( envelope, CRYPT_UNUSED, CRYPT_FORMAT_AUTO );
160  if( cryptStatusError( status ) )
161  {
162  printf( "cryptCreateDeevelope() failed with error code %d, line %d.\n",
163  status, __LINE__ );
164  return( FALSE );
165  }
166 
167  return( TRUE );
168  }
169 
170 static int addEnvInfoString( const CRYPT_ENVELOPE envelope,
172  const void *envInfo, const int envInfoLen )
173  {
174  int status;
175 
176  status = cryptSetAttributeString( envelope, type, envInfo, envInfoLen );
177  if( cryptStatusError( status ) )
178  {
179  printf( "cryptSetAttributeString() failed with error code %d, "
180  "line %d.\n", status, __LINE__ );
181  return( FALSE );
182  }
183 
184  return( TRUE );
185  }
186 
187 static int addEnvInfoNumeric( const CRYPT_ENVELOPE envelope,
188  const CRYPT_ATTRIBUTE_TYPE type,
189  const int envInfo )
190  {
191  int status;
192 
193  status = cryptSetAttribute( envelope, type, envInfo );
194  if( cryptStatusError( status ) )
195  {
196  printf( "cryptSetAttribute() of %d failed with error code %d, "
197  "line %d.\n", type, status, __LINE__ );
198  return( FALSE );
199  }
200 
201  return( TRUE );
202  }
203 
204 static int processEnvelopeResource( const CRYPT_ENVELOPE envelope,
205  const void *stringEnvInfo,
206  const int numericEnvInfo,
207  BOOLEAN *isRestartable )
208  {
209  int cryptEnvInfo, cryptAlgo, keySize = DUMMY_INIT;
210  int integrityLevel, status;
211 
212  /* Clear return value */
213  *isRestartable = FALSE;
214 
215  /* Add the appropriate enveloping information that we need to
216  continue */
219  if( cryptStatusError( status ) )
220  {
221  printf( "Attempt to move cursor to start of list failed with error "
222  "code %d, line %d.\n", status, __LINE__ );
223  return( status );
224  }
225  do
226  {
227  C_CHR label[ CRYPT_MAX_TEXTSIZE + 1 ];
228  int labelLength;
229 
230  status = cryptGetAttribute( envelope, CRYPT_ATTRIBUTE_CURRENT,
231  &cryptEnvInfo );
232  if( cryptStatusError( status ) )
233  {
234  printf( "Attempt to read current group failed with error code "
235  "%d, line %d.\n", status, __LINE__ );
236  return( status );
237  }
238 
239  switch( cryptEnvInfo )
240  {
242  /* The required information was supplied via other means (in
243  practice this means there's a crypto device available and
244  that was used for the decrypt), there's nothing left to
245  do */
246  puts( "(Decryption key was recovered using crypto device or "
247  "non-password-protected\n private key)." );
248  break;
249 
251  /* If there's no decryption password present, the private
252  key must be passed in directly */
253  if( stringEnvInfo == NULL )
254  {
255  status = cryptSetAttribute( envelope,
257  numericEnvInfo );
258  if( cryptStatusError( status ) )
259  {
260  printf( "Attempt to add private key failed with "
261  "error code %d, line %d.\n", status,
262  __LINE__ );
263  return( status );
264  }
265  *isRestartable = TRUE;
266  break;
267  }
268 
269  /* A private-key keyset is present in the envelope, we need
270  a password to decrypt the key */
271  status = cryptGetAttributeString( envelope,
273  label, &labelLength );
274  if( cryptStatusError( status ) )
275  {
276  printf( "Private key label read failed with error code "
277  "%d, line %d.\n", status, __LINE__ );
278  return( status );
279  }
280 #ifdef UNICODE_STRINGS
281  label[ labelLength / sizeof( wchar_t ) ] = '\0';
282  printf( "Need password to decrypt private key '%S'.\n",
283  label );
284 #else
285  label[ labelLength ] = '\0';
286  printf( "Need password to decrypt private key '%s'.\n",
287  label );
288 #endif /* UNICODE_STRINGS */
289  if( !addEnvInfoString( envelope, CRYPT_ENVINFO_PASSWORD,
290  stringEnvInfo, paramStrlen( stringEnvInfo ) ) )
291  return( SENTINEL );
292  *isRestartable = TRUE;
293  break;
294 
296  puts( "Need user password." );
297  if( !addEnvInfoString( envelope, CRYPT_ENVINFO_PASSWORD,
298  stringEnvInfo, paramStrlen( stringEnvInfo ) ) )
299  return( SENTINEL );
300  *isRestartable = TRUE;
301  break;
302 
304  puts( "Need session key." );
305  if( !addEnvInfoNumeric( envelope, CRYPT_ENVINFO_SESSIONKEY,
306  numericEnvInfo ) )
307  return( SENTINEL );
308  *isRestartable = TRUE;
309  break;
310 
311  case CRYPT_ENVINFO_KEY:
312  puts( "Need conventional encryption key." );
313  if( !addEnvInfoNumeric( envelope, CRYPT_ENVINFO_KEY,
314  numericEnvInfo ) )
315  return( SENTINEL );
316  *isRestartable = TRUE;
317  break;
318 
320  /* If we've processed the entire data block in one go, we
321  may end up with only signature information available, in
322  which case we defer processing them until after we've
323  finished with the deenveloped data */
324  break;
325 
326  default:
327  printf( "Need unknown enveloping information type %d.\n",
328  cryptEnvInfo );
329  return( SENTINEL );
330  }
331  }
334 
335  /* Check whether there's any integrity protection present */
336  status = cryptGetAttribute( envelope, CRYPT_ENVINFO_INTEGRITY,
337  &integrityLevel );
338  if( cryptStatusError( status ) )
339  {
340  printf( "Couldn't query integrity protection used in envelope, "
341  "status %d, line %d.\n", status, __LINE__ );
342  return( status );
343  }
344  if( integrityLevel > CRYPT_INTEGRITY_NONE )
345  {
346  printf( "Data is integrity-proteced using %s authentication.\n",
347  ( integrityLevel == CRYPT_INTEGRITY_MACONLY ) ? \
348  "MAC" : \
349  ( integrityLevel == CRYPT_INTEGRITY_FULL ) ? \
350  "MAC+encrypt" : "unknown" );
351  }
352 
353  /* If we're not using encryption, we're done */
354  if( cryptEnvInfo != CRYPT_ATTRIBUTE_NONE && \
355  cryptEnvInfo != CRYPT_ENVINFO_PRIVATEKEY && \
356  cryptEnvInfo != CRYPT_ENVINFO_PASSWORD )
357  return( CRYPT_OK );
358  if( integrityLevel == CRYPT_INTEGRITY_MACONLY )
359  return( CRYPT_OK );
360 
361  /* If we're using some form of encrypted enveloping, report the
362  algorithm and keysize used */
363  status = cryptGetAttribute( envelope, CRYPT_CTXINFO_ALGO, &cryptAlgo );
364  if( cryptStatusOK( status ) )
365  status = cryptGetAttribute( envelope, CRYPT_CTXINFO_KEYSIZE,
366  &keySize );
367  if( cryptStatusError( status ) )
368  {
369  printf( "Couldn't query encryption algorithm and keysize used in "
370  "envelope, status %d, line %d.\n", status, __LINE__ );
371  return( status );
372  }
373  printf( "Data is protected using algorithm %d with %d bit key.\n",
374  cryptAlgo, keySize * 8 );
375 
376  return( CRYPT_OK );
377  }
378 
379 static int pushData( const CRYPT_ENVELOPE envelope, const BYTE *buffer,
380  const int length, const void *stringEnvInfo,
381  const int numericEnvInfo )
382  {
383  int bytesIn, contentType, status;
384 
385  /* Push in the data */
386  status = cryptPushData( envelope, buffer, length, &bytesIn );
387  if( status == CRYPT_ENVELOPE_RESOURCE )
388  {
389  BOOLEAN isRestartable = FALSE;
390 
391  /* Process the required de-enveloping resource */
392  status = processEnvelopeResource( envelope, stringEnvInfo,
393  numericEnvInfo, &isRestartable );
394  if( cryptStatusError( status ) )
395  return( status );
396 
397  /* If we only got some of the data in due to the envelope stopping to
398  ask us for a decryption resource, push in the rest */
399  if( bytesIn < length && isRestartable )
400  {
401  const int initialBytesIn = bytesIn;
402 
403  status = cryptPushData( envelope, buffer + initialBytesIn,
404  length - initialBytesIn, &bytesIn );
405  if( cryptStatusError( status ) )
406  {
407  printf( "cryptPushData() for remaining data failed with "
408  "error code %d, line %d.\n", status, __LINE__ );
409  return( status );
410  }
411  bytesIn += initialBytesIn;
412  }
413  }
414  else
415  {
416  if( cryptStatusError( status ) )
417  {
418  printExtError( envelope, "cryptPushData()", status, __LINE__ );
419  return( status );
420  }
421  }
422  if( bytesIn < length )
423  {
424  BYTE tempBuffer[ 8192 ];
425  int bytesIn2, bytesOut;
426 
427  /* In the case of very large data quantities we may run out of
428  envelope buffer space during processing so we have to push the
429  remainder a second time. Removing some of the data destroys
430  the ability to compare the popped data with the input data later
431  on, but this is only done for the known self-test data and not
432  for import of arbitrary external data quantities */
433  printf( "(Ran out of input buffer data space, popping %d bytes to "
434  "make room).\n", 8192 );
435  status = cryptPopData( envelope, tempBuffer, 8192, &bytesOut );
436  if( cryptStatusError( status ) )
437  {
438  printf( "cryptPopData() to make way for remaining data failed "
439  "with error code %d, line %d.\n", status, __LINE__ );
440  return( status );
441  }
442  status = cryptPushData( envelope, buffer + bytesIn,
443  length - bytesIn, &bytesIn2 );
444  if( cryptStatusError( status ) )
445  {
446  printExtError( envelope, "cryptPushData() of remaining data",
447  status, __LINE__ );
448  return( status );
449  }
450  bytesIn += bytesIn2;
451  }
452  if( bytesIn != length )
453  {
454  printf( "cryptPushData() only copied %d of %d bytes, line %d.\n",
455  bytesIn, length, __LINE__ );
456  return( SENTINEL );
457  }
458 
459  /* Flush the data */
460  status = cryptFlushData( envelope );
461  if( cryptStatusError( status ) && status != CRYPT_ERROR_COMPLETE )
462  {
463  printExtError( envelope, "cryptFlushData()", status, __LINE__ );
464  return( status );
465  }
466 
467  /* Now that we've finished processing the data, report the inner content
468  type. We can't do in until this stage because some enveloping format
469  types encrypt the inner content type with the payload, so we can't
470  tell what it is until we've decrypted the payload */
471  status = cryptGetAttribute( envelope, CRYPT_ENVINFO_CONTENTTYPE,
472  &contentType );
473  if( cryptStatusError( status ) )
474  {
475  int value;
476 
477  /* A detached signature doesn't have any content to an inability to
478  determine the content type isn't a failure */
480  &value );
481  if( cryptStatusOK( status ) && value == TRUE )
482  {
483  puts( "(Data is from a detached signature, couldn't determine "
484  "content type)." );
485  return( bytesIn );
486  }
487  printf( "Couldn't query content type in envelope, status %d, "
488  "line %d.\n", status, __LINE__ );
489  return( status );
490  }
491  if( contentType != CRYPT_CONTENT_DATA )
492  printf( "Nested content type = %d.\n", contentType );
493 
494  return( bytesIn );
495  }
496 
497 static int popData( CRYPT_ENVELOPE envelope, BYTE *buffer, int bufferSize )
498  {
499  int status, bytesOut;
500 
501  status = cryptPopData( envelope, buffer, bufferSize, &bytesOut );
502  if( cryptStatusError( status ) )
503  {
504  printExtError( envelope, "cryptPopData()", status, __LINE__ );
505  return( status );
506  }
507 
508  return( bytesOut );
509  }
510 
511 static int destroyEnvelope( CRYPT_ENVELOPE envelope )
512  {
513  int status;
514 
515  /* Destroy the envelope */
516  status = cryptDestroyEnvelope( envelope );
517  if( cryptStatusError( status ) )
518  {
519  printf( "cryptDestroyEnvelope() failed with error code %d, line %d.\n",
520  status, __LINE__ );
521  return( FALSE );
522  }
523 
524  return( TRUE );
525  }
526 
527 /****************************************************************************
528 * *
529 * Data Enveloping Routines *
530 * *
531 ****************************************************************************/
532 
533 /* Test raw data enveloping */
534 
535 static int envelopeData( const char *dumpFileName,
536  const BOOLEAN useDatasize,
537  const int bufferSize,
538  const CRYPT_FORMAT_TYPE formatType )
539  {
540  CRYPT_ENVELOPE cryptEnvelope;
541  BYTE *inBufPtr, *outBufPtr = globalBuffer;
542  int length, bufSize, count;
543 
544  switch( bufferSize )
545  {
546  case 0:
547  printf( "Testing %splain data enveloping%s...\n",
548  ( formatType == CRYPT_FORMAT_PGP ) ? "PGP " : "",
549  ( useDatasize && ( formatType != CRYPT_FORMAT_PGP ) ) ? \
550  " with datasize hint" : "" );
551  length = ENVELOPE_TESTDATA_SIZE;
552  inBufPtr = ENVELOPE_TESTDATA;
553  break;
554 
555  case 1:
556  printf( "Testing %splain data enveloping of intermediate-size data...\n",
557  ( formatType == CRYPT_FORMAT_PGP ) ? "PGP " : "" );
558  length = 512;
559  inBufPtr = globalBuffer;
560  for( count = 0; count < length; count++ )
561  inBufPtr[ count ] = count & 0xFF;
562  break;
563 
564  case 2:
565  printf( "Testing %senveloping of large data quantity...\n",
566  ( formatType == CRYPT_FORMAT_PGP ) ? "PGP " : "" );
567 
568  /* Allocate a large buffer and fill it with a known value */
569  length = ( INT_MAX <= 32768L ) ? 16384 : 1048576;
570  if( ( inBufPtr = malloc( length + 128 ) ) == NULL )
571  {
572  printf( "Couldn't allocate buffer of %d bytes, skipping large "
573  "buffer enveloping test.\n", length );
574  return( TRUE );
575  }
576  outBufPtr = inBufPtr;
577  for( count = 0; count < length; count++ )
578  inBufPtr[ count ] = count & 0xFF;
579  break;
580 
581  default:
582  return( FALSE );
583  }
584  bufSize = length + 128;
585 
586  /* Create the envelope, push in the data, pop the enveloped result, and
587  destroy the envelope */
588  if( !createEnvelope( &cryptEnvelope, formatType ) )
589  return( FALSE );
590  if( useDatasize )
591  cryptSetAttribute( cryptEnvelope, CRYPT_ENVINFO_DATASIZE, length );
592  if( bufferSize > 1 )
594  length + 1024 );
595  count = pushData( cryptEnvelope, inBufPtr, length, NULL, 0 );
596  if( cryptStatusError( count ) )
597  return( FALSE );
598  count = popData( cryptEnvelope, outBufPtr, bufSize );
599  if( cryptStatusError( count ) )
600  return( FALSE );
601  if( !destroyEnvelope( cryptEnvelope ) )
602  return( FALSE );
603  if( bufferSize == 0 && \
604  count != length + ( ( formatType == CRYPT_FORMAT_PGP ) ? 8 : \
605  useDatasize ? 17 : 25 ) )
606  {
607  printf( "Enveloped data length %d, should be %d, line %d.\n",
608  count, length + 25, __LINE__ );
609  return( FALSE );
610  }
611 
612  /* Tell them what happened */
613  printf( "Enveloped data has size %d bytes.\n", count );
614  if( bufferSize < 2 )
615  debugDump( dumpFileName, outBufPtr, count );
616 
617  /* Create the envelope, push in the data, pop the de-enveloped result,
618  and destroy the envelope */
619  if( !createDeenvelope( &cryptEnvelope ) )
620  return( FALSE );
621  if( bufferSize > 1 )
623  length + 1024 );
624  count = pushData( cryptEnvelope, outBufPtr, count, NULL, 0 );
625  if( cryptStatusError( count ) )
626  return( FALSE );
627  count = popData( cryptEnvelope, outBufPtr, bufSize );
628  if( cryptStatusError( count ) )
629  return( FALSE );
630  if( !destroyEnvelope( cryptEnvelope ) )
631  return( FALSE );
632 
633  /* Make sure that the result matches what we pushed */
634  if( count != length )
635  {
636  puts( "De-enveloped data length != original length." );
637  return( FALSE );
638  }
639  if( bufferSize > 0 )
640  {
641  int i;
642 
643  for( i = 0; i < length; i++ )
644  if( outBufPtr[ i ] != ( i & 0xFF ) )
645  {
646  printf( "De-enveloped data != original data at byte %d, "
647  "line %d.\n", i, __LINE__ );
648  return( FALSE );
649  }
650  }
651  else
652  {
653  if( memcmp( outBufPtr, ENVELOPE_TESTDATA, length ) )
654  {
655  puts( "De-enveloped data != original data." );
656  return( FALSE );
657  }
658  }
659 
660  /* Clean up */
661  if( bufferSize > 1 )
662  free( inBufPtr );
663  puts( "Enveloping of plain data succeeded.\n" );
664  return( TRUE );
665  }
666 
667 int testEnvelopeData( void )
668  {
669  if( !envelopeData( "env_datn", FALSE, 0, CRYPT_FORMAT_CRYPTLIB ) )
670  return( FALSE ); /* Indefinite-length */
671  if( !envelopeData( "env_dat", TRUE, 0, CRYPT_FORMAT_CRYPTLIB ) )
672  return( FALSE ); /* Datasize */
673  if( !envelopeData( "env_dat.pgp", TRUE, 0, CRYPT_FORMAT_PGP ) )
674  return( FALSE ); /* PGP format */
675  return( envelopeData( "env_datl.pgp", TRUE, 1, CRYPT_FORMAT_PGP ) );
676  } /* PGP format, longer data */
677 
678 int testEnvelopeDataLargeBuffer( void )
679  {
680  if( !envelopeData( NULL, TRUE, 2, CRYPT_FORMAT_CRYPTLIB ) )
681  return( FALSE ); /* Datasize, large buffer */
682  return( envelopeData( NULL, TRUE, 2, CRYPT_FORMAT_PGP ) );
683  } /* Large buffer, PGP format */
684 
685 /* Test compressed enveloping */
686 
687 static int envelopeDecompress( BYTE *buffer, const int bufSize,
688  const int length )
689  {
690  CRYPT_ENVELOPE cryptEnvelope;
691  BYTE smallBuffer[ 128 ];
692  int count, zeroCount;
693 
694  /* Create the envelope, push in the data, and pop the de-enveloped
695  result */
696  if( !createDeenvelope( &cryptEnvelope ) )
697  return( FALSE );
698  count = pushData( cryptEnvelope, buffer, length, NULL, 0 );
699  if( cryptStatusError( count ) )
700  return( FALSE );
701  count = popData( cryptEnvelope, buffer, bufSize );
702  if( cryptStatusError( count ) )
703  {
704 #ifdef __hpux
705  if( count == -1 )
706  {
707  puts( "Older HPUX compilers break zlib, to remedy this you can "
708  "either get a better\ncompiler/OS or grab a debugger and "
709  "try to figure out what HPUX is doing to\nzlib. To "
710  "continue the self-tests, comment out the call to\n"
711  "testEnvelopeCompress() and rebuild." );
712  }
713 #endif /* __hpux */
714  return( FALSE );
715  }
716 
717  /* See what happens when we try and pop out more data. This test is done
718  because some compressed-data formats don't indicate the end of the
719  data properly, and we need to make sure that the de-enveloping code
720  handles this correctly */
721  zeroCount = popData( cryptEnvelope, smallBuffer, 128 );
722  if( zeroCount != 0 )
723  {
724  puts( "Attempt to pop more data after end-of-data had been reached "
725  "succeeded, the\nenvelope should have reported 0 bytes "
726  "available." );
727  return( FALSE );
728  }
729 
730  /* Clean up */
731  if( !destroyEnvelope( cryptEnvelope ) )
732  return( FALSE );
733  return( count );
734  }
735 
736 static int envelopeCompress( const char *dumpFileName,
737  const BOOLEAN useDatasize,
738  const CRYPT_FORMAT_TYPE formatType )
739  {
740  CRYPT_ENVELOPE cryptEnvelope;
741  FILE *inFile;
742  BYTE *buffer, *envelopedBuffer;
743  int dataCount = 0, count, status;
744 
745  printf( "Testing %scompressed data enveloping%s...\n",
746  ( formatType == CRYPT_FORMAT_PGP ) ? "PGP " : "",
747  useDatasize ? " with datasize hint" : "" );
748 
749  /* Since this needs a nontrivial amount of data for the compression, we
750  read it from an external file into dynamically-allocated buffers */
751  if( ( ( buffer = malloc( FILEBUFFER_SIZE ) ) == NULL ) || \
752  ( ( envelopedBuffer = malloc( FILEBUFFER_SIZE ) ) == NULL ) )
753  {
754  if( buffer != NULL )
755  free( buffer );
756  puts( "Couldn't allocate test buffers." );
757  return( FALSE );
758  }
759  inFile = fopen( convertFileName( COMPRESS_FILE ), "rb" );
760  if( inFile != NULL )
761  {
762  dataCount = fread( buffer, 1, FILEBUFFER_SIZE, inFile );
763  fclose( inFile );
764  assert( dataCount < FILEBUFFER_SIZE );
765  }
766  if( dataCount < 1000 || dataCount == FILEBUFFER_SIZE )
767  {
768  free( buffer );
769  free( envelopedBuffer );
770  puts( "Couldn't read test file for compression." );
771  return( FALSE );
772  }
773 
774  /* Create the envelope, push in the data, pop the enveloped result, and
775  destroy the envelope */
776  if( !createEnvelope( &cryptEnvelope, formatType ) )
777  return( FALSE );
778  status = cryptSetAttribute( cryptEnvelope, CRYPT_ENVINFO_COMPRESSION,
779  CRYPT_UNUSED );
780  if( cryptStatusError( status ) )
781  {
782  printf( "Attempt to enable compression failed, status = %d, "
783  "line %d.\n", status, __LINE__ );
784  return( FALSE );
785  }
786  if( useDatasize )
787  cryptSetAttribute( cryptEnvelope, CRYPT_ENVINFO_DATASIZE, dataCount );
788  count = pushData( cryptEnvelope, buffer, dataCount, NULL, 0 );
789  if( cryptStatusError( count ) )
790  return( FALSE );
791  count = popData( cryptEnvelope, envelopedBuffer, FILEBUFFER_SIZE );
792  if( count > dataCount - 1000 )
793  {
794  printf( "Compression of data failed, %d bytes in -> %d bytes out, "
795  "line %d.\n", dataCount, count, __LINE__ );
796  return( FALSE );
797  }
798  if( cryptStatusError( count ) )
799  return( FALSE );
800  if( !destroyEnvelope( cryptEnvelope ) )
801  return( FALSE );
802 
803  /* Tell them what happened */
804  printf( "Enveloped data has size %d bytes.\n", count );
805  debugDump( dumpFileName, envelopedBuffer, count );
806 
807  /* De-envelope the data and make sure that the result matches what we
808  pushed */
809  count = envelopeDecompress( envelopedBuffer, FILEBUFFER_SIZE, count );
810  if( count <= 0 )
811  return( FALSE );
812  if( count != dataCount || memcmp( buffer, envelopedBuffer, dataCount ) )
813  {
814  puts( "De-enveloped data != original data." );
815  return( FALSE );
816  }
817 
818  /* Clean up */
819  free( buffer );
820  free( envelopedBuffer );
821  puts( "Enveloping of compressed data succeeded.\n" );
822  return( TRUE );
823  }
824 
825 int testEnvelopeCompress( void )
826  {
827  /* In practice these two produce identical output since we always have to
828  use the indefinite-length encoding internally because we don't know in
829  advance how large the compressed data will be */
830  if( !envelopeCompress( "env_cprn", FALSE, CRYPT_FORMAT_CRYPTLIB ) )
831  return( FALSE ); /* Indefinite length */
832  if( !envelopeCompress( "env_cpr", TRUE, CRYPT_FORMAT_CRYPTLIB ) )
833  return( FALSE ); /* Datasize */
834  return( envelopeCompress( "env_cpr.pgp", TRUE, CRYPT_FORMAT_PGP ) );
835  } /* PGP format */
836 
837 /****************************************************************************
838 * *
839 * Encrypted Enveloping Routines *
840 * *
841 ****************************************************************************/
842 
843 /* Test encrypted enveloping with a raw session key */
844 
845 static int envelopeSessionCrypt( const char *dumpFileName,
846  const BOOLEAN useDatasize,
847  const BOOLEAN useStreamCipher,
848  const BOOLEAN useLargeBuffer,
849  const CRYPT_FORMAT_TYPE formatType )
850  {
851  CRYPT_ENVELOPE cryptEnvelope;
853  CRYPT_ALGO_TYPE cryptAlgo = ( formatType == CRYPT_FORMAT_PGP ) ? \
855  selectCipher( CRYPT_ALGO_AES );
856  BYTE *inBufPtr = ENVELOPE_TESTDATA, *outBufPtr = globalBuffer;
857 #if defined( __MSDOS16__ ) || defined( __WIN16__ )
858  const int length = useLargeBuffer ? 16384 : ENVELOPE_TESTDATA_SIZE;
859 #else
860  const int length = useLargeBuffer ? 1048576L : ENVELOPE_TESTDATA_SIZE;
861 #endif /* 16- vs.32-bit systems */
862  const int bufSize = length + 128;
863  int count, status;
864 
865  if( useLargeBuffer )
866  {
867  int i;
868 
869  printf( "Testing %sraw-session-key encrypted enveloping of large "
870  "data quantity...\n",
871  ( formatType == CRYPT_FORMAT_PGP ) ? "PGP " : "" );
872 
873  /* Allocate a large buffer and fill it with a known value */
874  if( ( inBufPtr = malloc( bufSize ) ) == NULL )
875  {
876  printf( "Couldn't allocate buffer of %d bytes, skipping large "
877  "buffer enveloping test.\n", length );
878  return( TRUE );
879  }
880  outBufPtr = inBufPtr;
881  for( i = 0; i < length; i++ )
882  inBufPtr[ i ] = i & 0xFF;
883  }
884  else
885  {
886  printf( "Testing %sraw-session-key encrypted enveloping%s...\n",
887  ( formatType == CRYPT_FORMAT_PGP ) ? "PGP " : "",
888  ( useStreamCipher ) ? " with stream cipher" : \
889  ( useDatasize && ( formatType != CRYPT_FORMAT_PGP ) ) ? \
890  " with datasize hint" : "" );
891  }
892 
893  if( formatType != CRYPT_FORMAT_PGP )
894  {
895  /* Create the session key context. We don't check for errors here
896  since this code will already have been tested earlier */
897  status = cryptCreateContext( &cryptContext, CRYPT_UNUSED,
898  cryptAlgo );
899  if( cryptStatusError( status ) )
900  return( FALSE );
901  }
902  else
903  {
904  /* PGP only allows a limited subset of algorithms and modes, in
905  addition we have to specifically check that IDEA is available
906  since it's possible to build cryptlib without IDEA support */
907  if( cryptAlgo != CRYPT_ALGO_IDEA )
908  {
909  puts( "Can't test PGP enveloping because the IDEA algorithm "
910  "isn't available in this\nbuild of cryptlib.\n" );
911  return( TRUE );
912  }
913  status = cryptCreateContext( &cryptContext, CRYPT_UNUSED,
914  cryptAlgo );
915  if( cryptStatusError( status ) )
916  return( FALSE );
917  cryptSetAttribute( cryptContext, CRYPT_CTXINFO_MODE,
918  CRYPT_MODE_CFB );
919  }
921  "0123456789ABCDEF", 16 );
922 
923  /* Create the envelope, push in a password and the data, pop the
924  enveloped result, and destroy the envelope */
925  if( !createEnvelope( &cryptEnvelope, formatType ) || \
926  !addEnvInfoNumeric( cryptEnvelope, CRYPT_ENVINFO_SESSIONKEY,
927  cryptContext ) )
928  return( FALSE );
929  if( useDatasize && !useLargeBuffer )
930  {
931  /* Test the ability to destroy the context after it's been added
932  (we replace it with a different context that's used later for
933  de-enveloping) */
934  cryptDestroyContext( cryptContext );
935  status = cryptCreateContext( &cryptContext, CRYPT_UNUSED,
936  cryptAlgo );
937  if( cryptStatusError( status ) )
938  return( FALSE );
940  "0123456789ABCDEF", 16 );
941 
942  /* As a side-effect, use the new context to test the rejection of
943  addition of a second session key */
944  if( addEnvInfoNumeric( cryptEnvelope, CRYPT_ENVINFO_SESSIONKEY,
945  cryptContext ) )
946  {
947  printf( "Addition of duplicate session key succeeded when it "
948  "should have failed,\nline %d.\n", __LINE__ );
949  return( FALSE );
950  }
951  puts( " (The above message indicates that the test condition was "
952  "successfully\n checked)." );
953  }
954  if( useDatasize )
955  cryptSetAttribute( cryptEnvelope, CRYPT_ENVINFO_DATASIZE, length );
956  if( useLargeBuffer )
958  length + 1024 );
959  count = pushData( cryptEnvelope, inBufPtr, length, NULL, 0 );
960  if( cryptStatusError( count ) )
961  return( FALSE );
962  count = popData( cryptEnvelope, outBufPtr, bufSize );
963  if( cryptStatusError( count ) )
964  return( FALSE );
965  if( !destroyEnvelope( cryptEnvelope ) )
966  return( FALSE );
967 
968  /* Tell them what happened */
969  printf( "Enveloped data has size %d bytes.\n", count );
970  if( !useLargeBuffer )
971  debugDump( dumpFileName, outBufPtr, count );
972 
973  /* Create the envelope, push in the data, pop the de-enveloped result,
974  and destroy the envelope */
975  if( !createDeenvelope( &cryptEnvelope ) )
976  return( FALSE );
977  if( useLargeBuffer )
979  length + 1024 );
980  count = pushData( cryptEnvelope, outBufPtr, count, NULL, cryptContext );
981  if( cryptStatusError( count ) )
982  return( FALSE );
983  count = popData( cryptEnvelope, outBufPtr, bufSize );
984  if( cryptStatusError( count ) )
985  return( FALSE );
986  if( !destroyEnvelope( cryptEnvelope ) )
987  return( FALSE );
988 
989  /* Make sure that the result matches what we pushed */
990  if( count != length )
991  {
992  puts( "De-enveloped data length != original length." );
993  return( FALSE );
994  }
995  if( useLargeBuffer )
996  {
997  int i;
998 
999  for( i = 0; i < length; i++ )
1000  if( outBufPtr[ i ] != ( i & 0xFF ) )
1001  {
1002  printf( "De-enveloped data != original data at byte %d, "
1003  "line %d.\n", i, __LINE__ );
1004  return( FALSE );
1005  }
1006  }
1007  else
1008  {
1009  if( memcmp( outBufPtr, ENVELOPE_TESTDATA, length ) )
1010  {
1011  puts( "De-enveloped data != original data." );
1012  return( FALSE );
1013  }
1014  }
1015 
1016  /* Clean up */
1017  if( useLargeBuffer )
1018  free( inBufPtr );
1019  cryptDestroyContext( cryptContext );
1020  puts( "Enveloping of raw-session-key-encrypted data succeeded.\n" );
1021  return( TRUE );
1022  }
1023 
1024 int testEnvelopeSessionCrypt( void )
1025  {
1026  if( !envelopeSessionCrypt( "env_sesn", FALSE, FALSE, FALSE, CRYPT_FORMAT_CRYPTLIB ) )
1027  return( FALSE ); /* Indefinite length */
1028  if( !envelopeSessionCrypt( "env_ses", TRUE, FALSE, FALSE, CRYPT_FORMAT_CRYPTLIB ) )
1029  return( FALSE ); /* Datasize */
1030  if( !envelopeSessionCrypt( "env_ses", TRUE, TRUE, FALSE, CRYPT_FORMAT_CRYPTLIB ) )
1031  return( FALSE ); /* Datasize, stream cipher */
1032 #if 0
1033  /* Although in theory PGP supports raw session-key based enveloping, in
1034  practice this key is always (implicitly) derived from a user password,
1035  so the enveloping code doesn't allow the use of raw session keys */
1036  return( envelopeSessionCrypt( "env_ses.pgp", TRUE, FALSE, FALSE, CRYPT_FORMAT_PGP ) );
1037 #endif /* 0 */
1038  return( TRUE );
1039  }
1040 
1042  {
1043  return( envelopeSessionCrypt( "env_ses", TRUE, FALSE, TRUE, CRYPT_FORMAT_CRYPTLIB ) );
1044  } /* Datasize, large buffer */
1045 
1046 /* Test encrypted enveloping */
1047 
1048 static int envelopeDecrypt( BYTE *buffer, const int length,
1049  const CRYPT_CONTEXT cryptContext )
1050  {
1051  CRYPT_ENVELOPE cryptEnvelope;
1052  int count;
1053 
1054  /* Create the envelope, push in the data, pop the de-enveloped result,
1055  and destroy the envelope */
1056  if( !createDeenvelope( &cryptEnvelope ) )
1057  return( FALSE );
1058  count = pushData( cryptEnvelope, buffer, length, NULL, cryptContext );
1059  if( cryptStatusError( count ) )
1060  return( FALSE );
1061  count = popData( cryptEnvelope, buffer, BUFFER_SIZE );
1062  if( cryptStatusError( count ) )
1063  return( FALSE );
1064  if( !destroyEnvelope( cryptEnvelope ) )
1065  return( FALSE );
1066  return( count );
1067  }
1068 
1069 static int envelopeCrypt( const char *dumpFileName,
1070  const BOOLEAN useDatasize,
1071  const CRYPT_FORMAT_TYPE formatType )
1072  {
1074  CRYPT_ENVELOPE cryptEnvelope;
1075  int count, status;
1076 
1077  printf( "Testing encrypted enveloping%s...\n",
1078  useDatasize ? " with datasize hint" : "" );
1079 
1080  /* Create the session key context. We don't check for errors here
1081  since this code will already have been tested earlier */
1082  status = cryptCreateContext( &cryptContext, CRYPT_UNUSED,
1083  CRYPT_ALGO_3DES );
1084  if( cryptStatusError( status ) )
1085  return( FALSE );
1087  "0123456789ABCDEF", 16 );
1088 
1089  /* Create the envelope, push in a KEK and the data, pop the enveloped
1090  result, and destroy the envelope */
1091  if( !createEnvelope( &cryptEnvelope, formatType ) || \
1092  !addEnvInfoNumeric( cryptEnvelope, CRYPT_ENVINFO_KEY, cryptContext ) )
1093  return( FALSE );
1094  if( useDatasize )
1095  cryptSetAttribute( cryptEnvelope, CRYPT_ENVINFO_DATASIZE,
1097  count = pushData( cryptEnvelope, ENVELOPE_TESTDATA,
1098  ENVELOPE_TESTDATA_SIZE, NULL, 0 );
1099  if( cryptStatusError( count ) )
1100  return( FALSE );
1101  count = popData( cryptEnvelope, globalBuffer, BUFFER_SIZE );
1102  if( cryptStatusError( count ) )
1103  return( FALSE );
1104  if( !destroyEnvelope( cryptEnvelope ) )
1105  return( FALSE );
1106 
1107  /* Tell them what happened */
1108  printf( "Enveloped data has size %d bytes.\n", count );
1109  debugDump( dumpFileName, globalBuffer, count );
1110 
1111  /* De-envelope the data and make sure that the result matches what we
1112  pushed */
1113  count = envelopeDecrypt( globalBuffer, count, cryptContext );
1114  if( count <= 0 )
1115  return( FALSE );
1116  if( count != ENVELOPE_TESTDATA_SIZE || \
1117  memcmp( globalBuffer, ENVELOPE_TESTDATA, ENVELOPE_TESTDATA_SIZE ) )
1118  {
1119  puts( "De-enveloped data != original data." );
1120  return( FALSE );
1121  }
1122 
1123  /* Clean up */
1124  cryptDestroyContext( cryptContext );
1125  puts( "Enveloping of encrypted data succeeded.\n" );
1126  return( TRUE );
1127  }
1128 
1129 int testEnvelopeCrypt( void )
1130  {
1131  if( !envelopeCrypt( "env_kekn", FALSE, CRYPT_FORMAT_CRYPTLIB ) )
1132  return( FALSE ); /* Indefinite length */
1133  return( envelopeCrypt( "env_kek", TRUE, CRYPT_FORMAT_CRYPTLIB ) );
1134  } /* Datasize */
1135 
1136 
1137 /* Test password-based encrypted enveloping */
1138 
1139 static int envelopePasswordDecrypt( BYTE *buffer, const int length )
1140  {
1141  CRYPT_ENVELOPE cryptEnvelope;
1142  int count;
1143 
1144  /* Create the envelope, push in the data, pop the de-enveloped result,
1145  and destroy the envelope */
1146  if( !createDeenvelope( &cryptEnvelope ) )
1147  return( FALSE );
1148  count = pushData( cryptEnvelope, buffer, length, TEST_PASSWORD,
1150  if( cryptStatusError( count ) )
1151  return( FALSE );
1152  count = popData( cryptEnvelope, buffer, BUFFER_SIZE );
1153  if( cryptStatusError( count ) )
1154  return( FALSE );
1155  if( !destroyEnvelope( cryptEnvelope ) )
1156  return( FALSE );
1157  return( count );
1158  }
1159 
1160 static int envelopePasswordCrypt( const char *dumpFileName,
1161  const BOOLEAN useDatasize,
1162  const BOOLEAN useAltCipher,
1163  const BOOLEAN multiKeys,
1164  const CRYPT_FORMAT_TYPE formatType )
1165  {
1166  CRYPT_ENVELOPE cryptEnvelope;
1167  int count;
1168 
1169  printf( "Testing %s%spassword-encrypted enveloping%s",
1170  ( formatType == CRYPT_FORMAT_PGP ) ? "PGP " : "",
1171  multiKeys ? "multiple-" : "",
1172  ( useDatasize && ( formatType != CRYPT_FORMAT_PGP ) ) ? \
1173  " with datasize hint" : "" );
1174  if( useAltCipher )
1175  {
1176  printf( ( formatType == CRYPT_FORMAT_PGP ) ? \
1177  " with non-default cipher type" : " and stream cipher" );
1178  }
1179  puts( "..." );
1180 
1181  /* Create the envelope, push in a password and the data, pop the
1182  enveloped result, and destroy the envelope */
1183  if( !createEnvelope( &cryptEnvelope, formatType ) || \
1184  !addEnvInfoString( cryptEnvelope, CRYPT_ENVINFO_PASSWORD,
1186  return( FALSE );
1187  if( useAltCipher )
1188  {
1190  int status;
1191 
1192  /* Test enveloping with an IV-less stream cipher, which tests the
1193  handling of algorithms that can't be used to wrap themselves in
1194  the RecipientInfo */
1195  status = cryptCreateContext( &sessionKeyContext, CRYPT_UNUSED,
1196  CRYPT_ALGO_RC4 );
1197  if( status == CRYPT_ERROR_NOTAVAIL )
1198  {
1199  puts( "Warning: Couldn't set non-default envelope cipher "
1200  "RC4, this may be disabled\n in this build of "
1201  "cryptlib.\n" );
1202  if( !destroyEnvelope( cryptEnvelope ) )
1203  return( FALSE );
1204  return( TRUE );
1205  }
1206  if( cryptStatusOK( status ) )
1207  status = cryptGenerateKey( sessionKeyContext );
1208  if( cryptStatusOK( status ) )
1209  {
1210  status = cryptSetAttribute( cryptEnvelope,
1212  sessionKeyContext );
1213  cryptDestroyContext( sessionKeyContext );
1214  }
1215  if( cryptStatusError( status ) )
1216  {
1217  printf( "Couldn't set non-default envelope cipher, error code "
1218  "%d, line %d.\n", status, __LINE__ );
1219  return( FALSE );
1220  }
1221  }
1222  if( multiKeys )
1223  {
1224  if( !addEnvInfoString( cryptEnvelope, CRYPT_ENVINFO_PASSWORD,
1225  TEXT( "Password1" ),
1226  paramStrlen( TEXT( "Password1" ) ) ) || \
1227  !addEnvInfoString( cryptEnvelope, CRYPT_ENVINFO_PASSWORD,
1228  TEXT( "Password2" ),
1229  paramStrlen( TEXT( "Password2" ) ) ) || \
1230  !addEnvInfoString( cryptEnvelope, CRYPT_ENVINFO_PASSWORD,
1231  TEXT( "Password3" ),
1232  paramStrlen( TEXT( "Password3" ) ) ) )
1233  return( FALSE );
1234  }
1235  if( useDatasize )
1236  cryptSetAttribute( cryptEnvelope, CRYPT_ENVINFO_DATASIZE,
1238  count = pushData( cryptEnvelope, ENVELOPE_TESTDATA,
1239  ENVELOPE_TESTDATA_SIZE, NULL, 0 );
1240  if( cryptStatusError( count ) )
1241  return( FALSE );
1242  count = popData( cryptEnvelope, globalBuffer, BUFFER_SIZE );
1243  if( cryptStatusError( count ) )
1244  return( FALSE );
1245  if( !destroyEnvelope( cryptEnvelope ) )
1246  return( FALSE );
1247 
1248  /* Tell them what happened */
1249  printf( "Enveloped data has size %d bytes.\n", count );
1250  debugDump( dumpFileName, globalBuffer, count );
1251 
1252  /* De-envelope the data and make sure that the result matches what we
1253  pushed */
1254  count = envelopePasswordDecrypt( globalBuffer, count );
1255  if( count <= 0 )
1256  return( FALSE );
1257  if( count != ENVELOPE_TESTDATA_SIZE || \
1258  memcmp( globalBuffer, ENVELOPE_TESTDATA, ENVELOPE_TESTDATA_SIZE ) )
1259  {
1260  puts( "De-enveloped data != original data." );
1261  return( FALSE );
1262  }
1263 
1264  /* Clean up */
1265  puts( "Enveloping of password-encrypted data succeeded.\n" );
1266  return( TRUE );
1267  }
1268 
1269 int testEnvelopePasswordCrypt( void )
1270  {
1271  if( !envelopePasswordCrypt( "env_pasn", FALSE, FALSE, FALSE, CRYPT_FORMAT_CRYPTLIB ) )
1272  return( FALSE ); /* Indefinite length */
1273  if( !envelopePasswordCrypt( "env_pas", TRUE, FALSE, FALSE, CRYPT_FORMAT_CRYPTLIB ) )
1274  return( FALSE ); /* Datasize */
1275  if( !envelopePasswordCrypt( "env_mpas", TRUE, FALSE, TRUE, CRYPT_FORMAT_CRYPTLIB ) )
1276  return( FALSE ); /* Datasize, multiple keys */
1277  if( !envelopePasswordCrypt( "env_pas.pgp", TRUE, FALSE, FALSE, CRYPT_FORMAT_PGP ) )
1278  return( FALSE ); /* PGP format */
1279  return( envelopePasswordCrypt( "env_pasr", TRUE, TRUE, FALSE, CRYPT_FORMAT_CRYPTLIB ) );
1280  } /* IV-less cipher */
1281 
1282 /* Test PKC-encrypted enveloping */
1283 
1284 static int envelopePKCDecrypt( BYTE *buffer, const int length,
1285  const KEYFILE_TYPE keyFileType,
1286  const CRYPT_HANDLE externalCryptKeyset )
1287  {
1288  CRYPT_ENVELOPE cryptEnvelope;
1289  CRYPT_KEYSET cryptKeyset;
1290  const C_STR keysetName;
1291  const C_STR password;
1292  int count, status;
1293 
1294  assert( ( keyFileType != KEYFILE_NONE && \
1295  externalCryptKeyset == CRYPT_UNUSED ) || \
1296  ( keyFileType == KEYFILE_NONE && \
1297  externalCryptKeyset != CRYPT_UNUSED ) );
1298 
1299  /* Create the envelope and push in the decryption keyset */
1300  if( !createDeenvelope( &cryptEnvelope ) )
1301  return( FALSE );
1302  if( keyFileType != KEYFILE_NONE )
1303  {
1304  keysetName = getKeyfileName( keyFileType, TRUE );
1305  password = getKeyfilePassword( keyFileType );
1306  status = cryptKeysetOpen( &cryptKeyset, CRYPT_UNUSED,
1307  CRYPT_KEYSET_FILE, keysetName,
1309  if( cryptStatusError( status ) )
1310  return( FALSE );
1311  }
1312  else
1313  {
1314  cryptKeyset = externalCryptKeyset;
1315  password = NULL;
1316  }
1317  status = addEnvInfoNumeric( cryptEnvelope, CRYPT_ENVINFO_KEYSET_DECRYPT,
1318  cryptKeyset );
1319  if( keyFileType != KEYFILE_NONE )
1320  cryptKeysetClose( cryptKeyset );
1321  if( status <= 0 )
1322  return( FALSE );
1323 
1324  /* Push in the data */
1325  count = pushData( cryptEnvelope, buffer, length, password, 0 );
1326  if( cryptStatusError( count ) )
1327  return( FALSE );
1328  count = popData( cryptEnvelope, buffer, BUFFER_SIZE );
1329  if( cryptStatusError( count ) )
1330  return( FALSE );
1331  if( !destroyEnvelope( cryptEnvelope ) )
1332  return( FALSE );
1333  return( count );
1334  }
1335 
1336 static int envelopePKCDecryptDirect( BYTE *buffer, const int length,
1337  const KEYFILE_TYPE keyFileType )
1338  {
1339  CRYPT_ENVELOPE cryptEnvelope;
1341  int count, status;
1342 
1343  /* Create the envelope and get the decryption key */
1344  if( !createDeenvelope( &cryptEnvelope ) )
1345  return( FALSE );
1346  status = getPrivateKey( &cryptContext,
1347  getKeyfileName( keyFileType, TRUE ),
1348  getKeyfileUserID( keyFileType, TRUE ),
1349  getKeyfilePassword( keyFileType ) );
1350  if( cryptStatusError( status ) )
1351  return( FALSE );
1352 
1353  /* Push in the data */
1354  count = pushData( cryptEnvelope, buffer, length, NULL, cryptContext );
1355  cryptDestroyContext( cryptContext );
1356  if( cryptStatusError( count ) )
1357  return( FALSE );
1358  count = popData( cryptEnvelope, buffer, BUFFER_SIZE );
1359  if( cryptStatusError( count ) )
1360  return( FALSE );
1361  if( !destroyEnvelope( cryptEnvelope ) )
1362  return( FALSE );
1363  return( count );
1364  }
1365 
1366 static int envelopePKCCrypt( const char *dumpFileName,
1367  const BOOLEAN useDatasize,
1368  const KEYFILE_TYPE keyFileType,
1369  const BOOLEAN useRecipient,
1370  const BOOLEAN useMultipleKeyex,
1371  const BOOLEAN useAltAlgo,
1372  const BOOLEAN useDirectKey,
1373  const CRYPT_FORMAT_TYPE formatType,
1374  const CRYPT_CONTEXT externalCryptContext,
1375  const CRYPT_HANDLE externalCryptKeyset )
1376  {
1377  CRYPT_ENVELOPE cryptEnvelope;
1378  CRYPT_KEYSET cryptKeyset;
1380  const C_STR keysetName = TEXT( "<None>" );
1381  const C_STR keyID = TEXT( "<None>" );
1382  int count, status;
1383 
1384  assert( ( keyFileType != KEYFILE_NONE && \
1385  externalCryptContext == CRYPT_UNUSED && \
1386  externalCryptKeyset == CRYPT_UNUSED ) || \
1387  ( keyFileType == KEYFILE_NONE && \
1388  externalCryptContext != CRYPT_UNUSED && \
1389  externalCryptKeyset != CRYPT_UNUSED ) );
1390 
1391  if( !keyReadOK )
1392  {
1393  puts( "Couldn't find key files, skipping test of public-key "
1394  "encrypted enveloping..." );
1395  return( TRUE );
1396  }
1397  if( keyFileType != KEYFILE_NONE )
1398  {
1399  /* When reading keys we have to explicitly use the first matching
1400  key in the PGP 2.x keyring since the remaining keys are (for some
1401  reason) stored unencrypted, and the keyring read code will
1402  disallow the use of the key if it's stored in this manner */
1403  keysetName = getKeyfileName( keyFileType, FALSE );
1404  keyID = ( keyFileType == KEYFILE_PGP ) ? \
1405  TEXT( "test" ) : getKeyfileUserID( keyFileType, FALSE );
1406  }
1407  printf( "Testing %spublic-key encrypted enveloping",
1408  ( formatType == CRYPT_FORMAT_PGP ) ? \
1409  ( ( keyFileType == KEYFILE_PGP ) ? "PGP " : "OpenPGP " ) : "" );
1410  if( useDatasize && ( formatType != CRYPT_FORMAT_PGP ) && \
1411  !( useRecipient || useMultipleKeyex || useDirectKey ) )
1412  printf( " with datasize hint" );
1413  printf( " using " );
1414  printf( ( keyFileType == KEYFILE_PGP ) ? \
1415  ( ( formatType == CRYPT_FORMAT_PGP ) ? \
1416  "PGP key" : "raw public key" ) : \
1417  "X.509 cert" );
1418  if( useRecipient && !useAltAlgo )
1419  printf( " and recipient info" );
1420  if( useMultipleKeyex )
1421  printf( " and additional keying info" );
1422  if( useAltAlgo )
1423  printf( " and alt.encr.algo" );
1424  if( useDirectKey )
1425  printf( " and direct key add" );
1426  puts( "..." );
1427 
1428  /* Open the keyset and either get the public key explicitly (to make sure
1429  that this version works) or leave the keyset open to allow it to be
1430  added to the envelope */
1431  if( keyFileType != KEYFILE_NONE )
1432  {
1433  status = cryptKeysetOpen( &cryptKeyset, CRYPT_UNUSED,
1434  CRYPT_KEYSET_FILE, keysetName,
1436  if( cryptStatusError( status ) )
1437  {
1438  printf( "Couldn't open keyset '%s', status %d, line %d.\n",
1439  keysetName, status, __LINE__ );
1440  return( FALSE );
1441  }
1442  if( !useRecipient )
1443  {
1444  status = cryptGetPublicKey( cryptKeyset, &cryptKey,
1445  CRYPT_KEYID_NAME, keyID );
1446  cryptKeysetClose( cryptKeyset );
1447  if( cryptStatusError( status ) )
1448  {
1449  puts( "Read of public key from file keyset failed." );
1450  return( FALSE );
1451  }
1452  }
1453  }
1454  else
1455  {
1456  cryptKey = externalCryptContext;
1457  cryptKeyset = externalCryptKeyset;
1458  }
1459 
1460  /* Create the envelope, push in the recipient info or public key and data,
1461  pop the enveloped result, and destroy the envelope */
1462  if( !createEnvelope( &cryptEnvelope, formatType ) )
1463  return( FALSE );
1464  if( useAltAlgo )
1465  {
1466  /* Specify the use of an alternative (non-default) bulk encryption
1467  algorithm */
1468  if( !addEnvInfoNumeric( cryptEnvelope, CRYPT_OPTION_ENCR_ALGO,
1470  return( FALSE );
1471  }
1472  if( useRecipient )
1473  {
1474  /* Add recipient information to the envelope. Since we can't
1475  guarantee for enveloping with cryptlib native key types that we
1476  have a real public-key keyset available at this time (it's created
1477  by a different part of the self-test code that may not have run
1478  yet) we're actually reading the public key from the private-key
1479  keyset. Normally we couldn't do this, however since PKCS #15
1480  doesn't store email addresses as key ID's (there's no need to),
1481  the code will drop back to trying for a match on the key label.
1482  Because of this we specify the private key label instead of a real
1483  recipient email address. Note that this trick only works because
1484  of a coincidence of two or three factors and wouldn't normally be
1485  used, it's only used here because we can't assume that a real
1486  public-key keyset is available for use.
1487 
1488  An additional test that would be useful is the ability to handle
1489  multiple key exchange records, however the keyset kludge makes
1490  this rather difficult. Since the functionality is tested by the
1491  use of multiple passwords in the conventional-encryption test
1492  earlier on this isn't a major issue */
1493  if( !addEnvInfoNumeric( cryptEnvelope, CRYPT_ENVINFO_KEYSET_ENCRYPT,
1494  cryptKeyset ) || \
1495  !addEnvInfoString( cryptEnvelope, CRYPT_ENVINFO_RECIPIENT,
1496  keyID, paramStrlen( keyID ) ) )
1497  return( FALSE );
1498  cryptKeysetClose( cryptKeyset );
1499  }
1500  else
1501  {
1502  if( !addEnvInfoNumeric( cryptEnvelope, CRYPT_ENVINFO_PUBLICKEY,
1503  cryptKey ) )
1504  return( FALSE );
1505 
1506  /* Test the ability to detect the addition of a duplicate key */
1507  if( !( useRecipient || useMultipleKeyex || useDirectKey ) )
1508  {
1509  if( addEnvInfoNumeric( cryptEnvelope, CRYPT_ENVINFO_PUBLICKEY,
1510  cryptKey ) )
1511  {
1512  printf( "Addition of duplicate key succeeded when it "
1513  "should have failed,\nline %d.\n", __LINE__ );
1514  return( FALSE );
1515  }
1516  puts( " (The above message indicates that the test condition "
1517  "was successfully\n checked)." );
1518  }
1519 
1520  if( keyFileType != KEYFILE_NONE )
1521  cryptDestroyObject( cryptKey );
1522  }
1523  if( useMultipleKeyex && \
1524  !addEnvInfoString( cryptEnvelope, CRYPT_ENVINFO_PASSWORD,
1525  TEXT( "test" ), paramStrlen( TEXT( "test" ) ) ) )
1526  return( FALSE );
1527  if( useDatasize )
1528  cryptSetAttribute( cryptEnvelope, CRYPT_ENVINFO_DATASIZE,
1530  count = pushData( cryptEnvelope, ENVELOPE_TESTDATA,
1531  ENVELOPE_TESTDATA_SIZE, NULL, 0 );
1532  if( cryptStatusError( count ) )
1533  return( FALSE );
1534  count = popData( cryptEnvelope, globalBuffer, BUFFER_SIZE );
1535  if( cryptStatusError( count ) )
1536  return( FALSE );
1537  if( !destroyEnvelope( cryptEnvelope ) )
1538  return( FALSE );
1539 
1540  /* Tell them what happened */
1541  printf( "Enveloped data has size %d bytes.\n", count );
1542  debugDump( dumpFileName, globalBuffer, count );
1543 
1544  /* De-envelope the data and make sure that the result matches what we
1545  pushed */
1546  if( useDirectKey )
1547  count = envelopePKCDecryptDirect( globalBuffer, count, keyFileType );
1548  else
1549  count = envelopePKCDecrypt( globalBuffer, count, keyFileType, externalCryptKeyset );
1550  if( count <= 0 )
1551  return( FALSE );
1552  if( count != ENVELOPE_TESTDATA_SIZE || \
1553  memcmp( globalBuffer, ENVELOPE_TESTDATA, ENVELOPE_TESTDATA_SIZE ) )
1554  {
1555  puts( "De-enveloped data != original data." );
1556  return( FALSE );
1557  }
1558 
1559  /* Clean up */
1560  puts( "Enveloping of public-key encrypted data succeeded.\n" );
1561  return( TRUE );
1562  }
1563 
1564 int testEnvelopePKCCrypt( void )
1565  {
1567  {
1568  puts( "Skipping raw public-key and PGP enveloping, which requires "
1569  "the IDEA cipher to\nbe enabled.\n" );
1570  }
1571  else
1572  {
1573  if( !envelopePKCCrypt( "env_pkcn", FALSE, KEYFILE_PGP, FALSE, FALSE, FALSE, FALSE, CRYPT_FORMAT_CRYPTLIB, CRYPT_UNUSED, CRYPT_UNUSED ) )
1574  return( FALSE ); /* Indefinite length, raw key */
1575  if( !envelopePKCCrypt( "env_pkc", TRUE, KEYFILE_PGP, FALSE, FALSE, FALSE, FALSE, CRYPT_FORMAT_CRYPTLIB, CRYPT_UNUSED, CRYPT_UNUSED ) )
1576  return( FALSE ); /* Datasize, raw key */
1577  if( !envelopePKCCrypt( "env_pkc.pgp", TRUE, KEYFILE_PGP, FALSE, FALSE, FALSE, FALSE, CRYPT_FORMAT_PGP, CRYPT_UNUSED, CRYPT_UNUSED ) )
1578  return( FALSE ); /* PGP format */
1579  if( !envelopePKCCrypt( "env_pkc.pgp", TRUE, KEYFILE_PGP, TRUE, FALSE, FALSE, FALSE, CRYPT_FORMAT_PGP, CRYPT_UNUSED, CRYPT_UNUSED ) )
1580  return( FALSE ); /* PGP format, recipient */
1581  if( !envelopePKCCrypt( "env_pkca.pgp", TRUE, KEYFILE_PGP, TRUE, FALSE, TRUE, FALSE, CRYPT_FORMAT_PGP, CRYPT_UNUSED, CRYPT_UNUSED ) )
1582  return( FALSE ); /* PGP format, recipient, nonstandard bulk encr.algo */
1583  }
1584  if( !envelopePKCCrypt( "env_crt.pgp", TRUE, KEYFILE_X509, TRUE, FALSE, FALSE, FALSE, CRYPT_FORMAT_PGP, CRYPT_UNUSED, CRYPT_UNUSED ) )
1585  return( FALSE ); /* PGP format, certificate */
1586  if( !envelopePKCCrypt( "env_crtn", FALSE, KEYFILE_X509, FALSE, FALSE, FALSE, FALSE, CRYPT_FORMAT_CRYPTLIB, CRYPT_UNUSED, CRYPT_UNUSED ) )
1587  return( FALSE ); /* Indefinite length, certificate */
1588  if( !envelopePKCCrypt( "env_crt", TRUE, KEYFILE_X509, FALSE, FALSE, FALSE, FALSE, CRYPT_FORMAT_CRYPTLIB, CRYPT_UNUSED, CRYPT_UNUSED ) )
1589  return( FALSE ); /* Datasize, certificate */
1590  if( !envelopePKCCrypt( "env_crt", TRUE, KEYFILE_X509, FALSE, FALSE, FALSE, TRUE, CRYPT_FORMAT_CRYPTLIB, CRYPT_UNUSED, CRYPT_UNUSED ) )
1591  return( FALSE ); /* Datasize, certificate, decrypt key provided directly */
1592  if( !envelopePKCCrypt( "env_crt", TRUE, KEYFILE_X509, TRUE, FALSE, FALSE, FALSE, CRYPT_FORMAT_CRYPTLIB, CRYPT_UNUSED, CRYPT_UNUSED ) )
1593  return( FALSE ); /* Datasize, cerficate, recipient */
1594  return( envelopePKCCrypt( "env_crtp", TRUE, KEYFILE_X509, FALSE, TRUE, FALSE, FALSE, CRYPT_FORMAT_CRYPTLIB, CRYPT_UNUSED, CRYPT_UNUSED ) );
1595  } /* Datasize, cerficate+password */
1596 
1597 int testEnvelopePKCCryptEx( const CRYPT_CONTEXT cryptContext,
1598  const CRYPT_HANDLE decryptKeyset )
1599  {
1600  /* Note that we can't test PGP enveloping with device-based keys since
1601  the PGP keyIDs aren't supported by any known device type */
1602 #if 0
1603  if( !envelopePKCCrypt( "env_pkc.pgp", TRUE, KEYFILE_NONE, FALSE, FALSE, FALSE, FALSE, CRYPT_FORMAT_PGP, cryptContext, decryptKeyset ) )
1604  return( FALSE ); /* PGP format */
1605 #endif
1606  return( envelopePKCCrypt( "env_pkc", TRUE, KEYFILE_NONE, FALSE, FALSE, FALSE, FALSE, CRYPT_FORMAT_CRYPTLIB, cryptContext, decryptKeyset ) );
1607  } /* Datasize, raw key */
1608 
1609 /* Test each encryption algorithm */
1610 
1611 static int envelopeAlgoCrypt( const char *dumpFileName,
1612  const CRYPT_ALGO_TYPE cryptAlgo )
1613  {
1614  CRYPT_ENVELOPE cryptEnvelope;
1615  CRYPT_HANDLE encryptKey, decryptKey;
1616  const char *algoName = \
1617  ( cryptAlgo == CRYPT_ALGO_RSA ) ? "RSA" : \
1618  ( cryptAlgo == CRYPT_ALGO_ELGAMAL ) ? "Elgamal" : "<Unknown>";
1619  int count;
1620 
1621  printf( "Testing %s public-key encrypted enveloping...\n", algoName );
1622 
1623  /* Create the en/decryption contexts */
1624  switch( cryptAlgo )
1625  {
1626  case CRYPT_ALGO_RSA:
1627  if( !loadRSAContexts( CRYPT_UNUSED, &encryptKey, &decryptKey ) )
1628  return( FALSE );
1629  break;
1630 
1631  case CRYPT_ALGO_ELGAMAL:
1632  if( !loadElgamalContexts( &encryptKey, &decryptKey ) )
1633  return( FALSE );
1634  break;
1635 
1636  default:
1637  printf( "Unknown encryption algorithm %d, line %d.\n",
1638  cryptAlgo, __LINE__ );
1639  return( FALSE );
1640  }
1641 
1642  /* Create the envelope, push in the public key and data, pop the
1643  enveloped result, and destroy the envelope */
1644  if( !createEnvelope( &cryptEnvelope, CRYPT_FORMAT_CRYPTLIB ) )
1645  return( FALSE );
1646  if( !addEnvInfoNumeric( cryptEnvelope, CRYPT_ENVINFO_PUBLICKEY,
1647  encryptKey ) )
1648  return( FALSE );
1649  cryptDestroyContext( encryptKey );
1650  cryptSetAttribute( cryptEnvelope, CRYPT_ENVINFO_DATASIZE,
1652  count = pushData( cryptEnvelope, ENVELOPE_TESTDATA,
1653  ENVELOPE_TESTDATA_SIZE, NULL, 0 );
1654  if( cryptStatusError( count ) )
1655  return( FALSE );
1656  count = popData( cryptEnvelope, globalBuffer, BUFFER_SIZE );
1657  if( cryptStatusError( count ) )
1658  return( FALSE );
1659  if( !destroyEnvelope( cryptEnvelope ) )
1660  return( FALSE );
1661 
1662  /* Tell them what happened */
1663  printf( "%s-enveloped data has size %d bytes.\n", algoName, count );
1664  debugDump( dumpFileName, globalBuffer, count );
1665 
1666  /* De-envelope the data and make sure that the result matches what we
1667  pushed */
1668  if( !createDeenvelope( &cryptEnvelope ) )
1669  return( FALSE );
1670  count = pushData( cryptEnvelope, globalBuffer, count, NULL,
1671  decryptKey );
1672  cryptDestroyContext( decryptKey );
1673  if( cryptStatusError( count ) )
1674  return( FALSE );
1675  count = popData( cryptEnvelope, globalBuffer, BUFFER_SIZE );
1676  if( cryptStatusError( count ) )
1677  return( FALSE );
1678  if( !destroyEnvelope( cryptEnvelope ) )
1679  return( FALSE );
1680  if( count != ENVELOPE_TESTDATA_SIZE || \
1681  memcmp( globalBuffer, ENVELOPE_TESTDATA, ENVELOPE_TESTDATA_SIZE ) )
1682  {
1683  puts( "De-enveloped data != original data." );
1684  return( FALSE );
1685  }
1686 
1687  /* Clean up */
1688  puts( "Enveloping of public-key encrypted data succeeded.\n" );
1689  return( TRUE );
1690  }
1691 
1692 int testEnvelopePKCCryptAlgo( void )
1693  {
1694  if( !envelopeAlgoCrypt( "env_pkc_rsa", CRYPT_ALGO_RSA ) )
1695  return( FALSE );
1697  !envelopeAlgoCrypt( "env_pkc_elg", CRYPT_ALGO_ELGAMAL ) )
1698  return( FALSE );
1699  return( TRUE );
1700  }
1701 
1702 /****************************************************************************
1703 * *
1704 * Signed Enveloping Routines *
1705 * *
1706 ****************************************************************************/
1707 
1708 /* Test signed enveloping */
1709 
1710 static int getSigCheckResult( const CRYPT_ENVELOPE cryptEnvelope,
1712  const BOOLEAN showAttributes,
1713  const BOOLEAN isAuthData )
1714  {
1715  int value, status;
1716 
1717  /* Display all of the attributes that we've got */
1718  if( showAttributes && !displayAttributes( cryptEnvelope ) )
1719  return( FALSE );
1720 
1721  /* Determine the result of the signature check. If it's authenticated
1722  data there's no need to do anything with keys, if it's signed data
1723  we have to do some extra processing */
1724  if( !isAuthData )
1725  {
1726  status = cryptGetAttribute( cryptEnvelope, CRYPT_ATTRIBUTE_CURRENT,
1727  &value );
1728  if( cryptStatusError( status ) )
1729  {
1730  printf( "Read of required attribute for signature check "
1731  "returned status %d, line %d.\n", status, __LINE__ );
1732  return( FALSE );
1733  }
1734  if( value != CRYPT_ENVINFO_SIGNATURE )
1735  {
1736  printf( "Envelope requires unexpected enveloping information "
1737  "type %d, line %d.\n", value, __LINE__ );
1738  return( FALSE );
1739  }
1740  if( sigCheckContext != CRYPT_UNUSED )
1741  {
1742  status = cryptSetAttribute( cryptEnvelope, CRYPT_ENVINFO_SIGNATURE,
1743  sigCheckContext );
1744  if( cryptStatusError( status ) )
1745  {
1746  printf( "Attempt to add signature check key returned status "
1747  "%d, line %d.\n", status, __LINE__ );
1748  return( FALSE );
1749  }
1750  }
1751  }
1752  status = cryptGetAttribute( cryptEnvelope, CRYPT_ENVINFO_SIGNATURE_RESULT,
1753  &value );
1754  if( cryptStatusError( status ) )
1755  {
1756  printf( "Signature check returned status %d, line %d.\n", status,
1757  __LINE__ );
1758  return( FALSE );
1759  }
1760  switch( value )
1761  {
1762  case CRYPT_OK:
1763  puts( "Signature is valid." );
1764  return( TRUE );
1765 
1766  case CRYPT_ERROR_NOTFOUND:
1767  puts( "Cannot find key to check signature." );
1768  break;
1769 
1770  case CRYPT_ERROR_SIGNATURE:
1771  puts( "Signature is invalid." );
1772  break;
1773 
1774  case CRYPT_ERROR_NOTAVAIL:
1775  puts( "Warning: Couldn't verify signature due to use of a "
1776  "deprecated/insecure\n signature algorithm.\n" );
1777  return( TRUE );
1778 
1779  default:
1780  printf( "Signature check failed, result = %d, line %d.\n",
1781  value, __LINE__ );
1782  }
1783 
1784  return( FALSE );
1785  }
1786 
1787 static int envelopeSigCheck( BYTE *buffer, const int length,
1788  const CRYPT_CONTEXT hashContext,
1789  const CRYPT_CONTEXT sigContext,
1790  const KEYFILE_TYPE keyFileType,
1791  const BOOLEAN detachedSig,
1792  const CRYPT_FORMAT_TYPE formatType )
1793  {
1794  CRYPT_ENVELOPE cryptEnvelope;
1795  int count, status;
1796 
1797  /* Create the envelope and push in the sig.check keyset if we're not
1798  using a supplied context for the sig.check */
1799  if( !createDeenvelope( &cryptEnvelope ) )
1800  return( FALSE );
1801  if( sigContext == CRYPT_UNUSED )
1802  {
1803  const C_STR keysetName = getKeyfileName( keyFileType, FALSE );
1804  CRYPT_KEYSET cryptKeyset;
1805 
1806  status = cryptKeysetOpen( &cryptKeyset, CRYPT_UNUSED,
1807  CRYPT_KEYSET_FILE, keysetName,
1809  if( cryptStatusOK( status ) )
1810  status = addEnvInfoNumeric( cryptEnvelope,
1811  CRYPT_ENVINFO_KEYSET_SIGCHECK, cryptKeyset );
1812  cryptKeysetClose( cryptKeyset );
1813  if( status <= 0 )
1814  return( FALSE );
1815  }
1816 
1817  /* If the hash value is being supplied externally, add it to the envelope
1818  before we add the signature data */
1819  if( detachedSig && hashContext != CRYPT_UNUSED )
1820  {
1821  status = cryptSetAttribute( cryptEnvelope, CRYPT_ENVINFO_HASH,
1822  hashContext );
1823  if( cryptStatusError( status ) )
1824  {
1825  printf( "Couldn't add externally-generated hash value to "
1826  "envelope, status %d, line %d.\n", status, __LINE__ );
1827  return( FALSE );
1828  }
1829  }
1830 
1831  /* Push in the data */
1832  count = pushData( cryptEnvelope, buffer, length, NULL, 0 );
1833  if( !cryptStatusError( count ) )
1834  {
1835  if( detachedSig )
1836  {
1837  if( hashContext == CRYPT_UNUSED )
1838  count = pushData( cryptEnvelope, ENVELOPE_TESTDATA,
1839  ENVELOPE_TESTDATA_SIZE, NULL, 0 );
1840  }
1841  else
1842  count = popData( cryptEnvelope, buffer, length );
1843  }
1844  if( cryptStatusError( count ) )
1845  return( FALSE );
1846 
1847  /* Determine the result of the signature check */
1848  if( !getSigCheckResult( cryptEnvelope, sigContext, TRUE, FALSE ) )
1849  return( FALSE );
1850 
1851  /* If we supplied the sig-checking key, make sure that it's handled
1852  correctly by the envelope. We shouldn't be able to read it back from
1853  a PGP envelope, and from a cryptlib/CMS/SMIME envelope we should get
1854  back only a certificate, not the full private key that we added */
1855  if( sigContext != CRYPT_UNUSED )
1856  {
1858 
1859  status = cryptGetAttribute( cryptEnvelope, CRYPT_ENVINFO_SIGNATURE,
1860  &sigCheckContext );
1861  if( formatType == CRYPT_FORMAT_PGP )
1862  {
1863  /* If it's a PGP envelope, we can't retrieve the signing key from
1864  it */
1865  if( cryptStatusOK( status ) )
1866  {
1867  printf( "Attempt to read signature check key from PGP "
1868  "envelope succeeded when it\nshould have failed, "
1869  "line %d.\n", __LINE__ );
1870  return( FALSE );
1871  }
1872  }
1873  else
1874  {
1875  CRYPT_ENVELOPE testEnvelope;
1876 
1877  /* If it's a cryptlib/CMS/SMIME envelope then we should be able
1878  to retrieve the signing key from it */
1879  if( cryptStatusError( status ) )
1880  {
1881  printf( "Couldn't retrieve signature check key from "
1882  "envelope, status %d, line %d.\n", status,
1883  __LINE__ );
1884  return( FALSE );
1885  }
1886 
1887  /* The signing key should be a pure certificate, not the private
1888  key+certificate combination that we pushed in. Note that the
1889  following will result in an error message being printed in
1890  addEnvInfoNumeric() */
1891  createEnvelope( &testEnvelope, CRYPT_FORMAT_CRYPTLIB );
1892  if( addEnvInfoNumeric( testEnvelope, CRYPT_ENVINFO_SIGNATURE,
1893  sigCheckContext ) )
1894  {
1895  printf( "Retrieved signature check key is a private key, not "
1896  "a certificate, line %d.\n", __LINE__ );
1897  return( FALSE );
1898  }
1899  else
1900  {
1901  puts( " (The above message indicates that the test "
1902  "condition was successfully\n checked)." );
1903  }
1904  if( !destroyEnvelope( testEnvelope ) )
1905  return( FALSE );
1906  cryptDestroyCert( sigCheckContext );
1907  }
1908  }
1909 
1910  /* Clean up */
1911  if( !destroyEnvelope( cryptEnvelope ) )
1912  return( FALSE );
1913  return( count );
1914  }
1915 
1916 static int envelopeSign( const void *data, const int dataLength,
1917  const char *dumpFileName,
1918  const KEYFILE_TYPE keyFileType,
1919  const BOOLEAN useDatasize,
1920  const BOOLEAN useCustomHash,
1921  const BOOLEAN useSuppliedKey,
1922  const CRYPT_FORMAT_TYPE formatType )
1923  {
1924  CRYPT_ENVELOPE cryptEnvelope;
1925  CRYPT_KEYSET cryptKeyset;
1926  CRYPT_CONTEXT cryptContext = DUMMY_INIT;
1927  int count, status;
1928 
1929  if( !keyReadOK )
1930  {
1931  puts( "Couldn't find key files, skipping test of signed "
1932  "enveloping..." );
1933  return( TRUE );
1934  }
1935  printf( "Testing %ssigned enveloping%s",
1936  ( formatType == CRYPT_FORMAT_PGP ) ? "PGP " : \
1937  ( formatType == CRYPT_FORMAT_SMIME ) ? "S/MIME " : "",
1938  ( useDatasize && ( formatType != CRYPT_FORMAT_PGP ) ) ? \
1939  " with datasize hint" : "" );
1940  if( useCustomHash )
1941  printf( " %s custom hash",
1942  ( formatType == CRYPT_FORMAT_PGP ) ? "with" :"and" );
1943  printf( " using %s",
1944  ( keyFileType == KEYFILE_OPENPGP_HASH ) ? "raw DSA key" : \
1945  ( keyFileType == KEYFILE_PGP ) ? "raw public key" : \
1946  useSuppliedKey ? "supplied X.509 cert" : "X.509 cert" );
1947  puts( "..." );
1948 
1949  /* Get the private key */
1950  if( keyFileType == KEYFILE_OPENPGP_HASH || keyFileType == KEYFILE_PGP )
1951  {
1952  const C_STR keysetName = getKeyfileName( keyFileType, TRUE );
1953 
1954  status = cryptKeysetOpen( &cryptKeyset, CRYPT_UNUSED,
1955  CRYPT_KEYSET_FILE, keysetName,
1957  if( cryptStatusOK( status ) )
1958  {
1959  status = cryptGetPrivateKey( cryptKeyset, &cryptContext,
1963  cryptKeysetClose( cryptKeyset );
1964  }
1965  }
1966  else
1967  {
1968  status = getPrivateKey( &cryptContext, USER_PRIVKEY_FILE,
1970  }
1971  if( cryptStatusError( status ) )
1972  {
1973  printf( "Read of private key from key file failed, status %d, "
1974  "line %d, cannot test enveloping.\n", status, __LINE__ );
1975  return( FALSE );
1976  }
1977 
1978  /* Create the envelope, push in the signing key, any extra information,
1979  and the data to sign, pop the enveloped result, and destroy the
1980  envelope */
1981  if( !createEnvelope( &cryptEnvelope, formatType ) )
1982  return( FALSE );
1983  if( useCustomHash )
1984  {
1986 
1987  /* Add the (nonstandard) hash algorithm information. We need to do
1988  this before we add the signing key since it's automatically
1989  associated with the last hash algorithm added */
1990  status = cryptCreateContext( &hashContext, CRYPT_UNUSED,
1992  if( cryptStatusError( status ) )
1993  return( FALSE );
1994  status = addEnvInfoNumeric( cryptEnvelope, CRYPT_ENVINFO_HASH,
1995  hashContext );
1996  if( status <= 0 )
1997  return( FALSE );
1998 
1999  /* Test the ability to reject a duplicate add of the same hash */
2000  status = addEnvInfoNumeric( cryptEnvelope, CRYPT_ENVINFO_HASH,
2001  hashContext );
2002  cryptDestroyContext( hashContext );
2003  if( status > 0 )
2004  {
2005  printf( "Addition of duplicate hash succeeded when it should "
2006  "have failed, line %d.\n", __LINE__ );
2007  return( FALSE );
2008  }
2009  puts( " (The above message indicates that the test condition was "
2010  "successfully\n checked)." );
2011  }
2012  if( !addEnvInfoNumeric( cryptEnvelope, CRYPT_ENVINFO_SIGNATURE,
2013  cryptContext ) )
2014  return( FALSE );
2015  if( useDatasize && !useCustomHash && \
2016  !( keyFileType == KEYFILE_OPENPGP_HASH || keyFileType == KEYFILE_PGP ) && \
2017  ( formatType != CRYPT_FORMAT_PGP ) )
2018  {
2020 
2021  /* Make sure that adding a (pseudo-duplicate) hash action that
2022  duplicates the one already added implicitly by the addition of
2023  the signature key succeeds (internally, nothing is really done
2024  since the hash action is already present) */
2025  status = cryptCreateContext( &hashContext, CRYPT_UNUSED,
2026  CRYPT_ALGO_SHA );
2027  if( cryptStatusError( status ) )
2028  return( FALSE );
2029  status = addEnvInfoNumeric( cryptEnvelope, CRYPT_ENVINFO_HASH,
2030  hashContext );
2031  cryptDestroyContext( hashContext );
2032  if( status <= 0 )
2033  return( FALSE );
2034  }
2035  if( cryptSetAttribute( cryptEnvelope, CRYPT_ENVINFO_SIGNATURE,
2036  cryptContext ) != CRYPT_ERROR_INITED )
2037  {
2038  puts( "Addition of duplicate key to envelope wasn't detected." );
2039  return( FALSE );
2040  }
2041  if( !useSuppliedKey )
2042  cryptDestroyContext( cryptContext );
2043  if( useDatasize )
2044  cryptSetAttribute( cryptEnvelope, CRYPT_ENVINFO_DATASIZE,
2045  dataLength );
2046  count = pushData( cryptEnvelope, data, dataLength, NULL, 0 );
2047  if( cryptStatusError( count ) )
2048  return( FALSE );
2049  count = popData( cryptEnvelope, globalBuffer, BUFFER_SIZE );
2050  if( cryptStatusError( count ) )
2051  return( FALSE );
2052  if( !destroyEnvelope( cryptEnvelope ) )
2053  return( FALSE );
2054 
2055  /* Tell them what happened */
2056  printf( "Enveloped data has size %d bytes.\n", count );
2057  debugDump( dumpFileName, globalBuffer, count );
2058 
2059  /* De-envelope the data and make sure that the result matches what we
2060  pushed */
2061  count = envelopeSigCheck( globalBuffer, count, CRYPT_UNUSED,
2062  ( useSuppliedKey ) ? cryptContext : CRYPT_UNUSED,
2063  keyFileType, FALSE, formatType );
2064  if( count <= 0 )
2065  return( FALSE );
2066  if( count != dataLength || memcmp( globalBuffer, data, dataLength ) )
2067  {
2068  puts( "De-enveloped data != original data." );
2069  return( FALSE );
2070  }
2071  if( useSuppliedKey )
2072  {
2073  /* If the following fails, there's a problem with handling reference
2074  counting for keys */
2075  status = cryptDestroyContext( cryptContext );
2076  if( cryptStatusError( status ) )
2077  {
2078  printf( "Attempt to destroy externally-added sig.check key "
2079  "returned %d, line %d.\n", status, __LINE__ );
2080  return( FALSE );
2081  }
2082  }
2083 
2084  /* Clean up */
2085  puts( "Enveloping of signed data succeeded.\n" );
2086  return( TRUE );
2087  }
2088 
2089 int testEnvelopeSign( void )
2090  {
2092  puts( "Skipping raw public-key based signing, which requires the "
2093  "IDEA cipher to\nbe enabled.\n" );
2094  else
2095  {
2097  return( FALSE ); /* Indefinite length, raw key */
2099  return( FALSE ); /* Datasize, raw key */
2100  if( !envelopeSign( ENVELOPE_TESTDATA, ENVELOPE_TESTDATA_SIZE, "env_sig.pgp", KEYFILE_PGP, TRUE, FALSE, FALSE, CRYPT_FORMAT_PGP ) )
2101  return( FALSE ); /* PGP format, raw key */
2103  return( FALSE ); /* PGP format, raw DSA key */
2104  }
2106  return( FALSE ); /* Indefinite length, certificate */
2108  return( FALSE ); /* Datasize, certificate */
2110  return( FALSE ); /* Datasize, certificate, S/MIME semantics */
2112  return( FALSE ); /* Datasize, certificate, sigcheck key supplied */
2113  if( !envelopeSign( ENVELOPE_TESTDATA, ENVELOPE_TESTDATA_SIZE, "env_csg.pgp", KEYFILE_X509, TRUE, FALSE, FALSE, CRYPT_FORMAT_PGP ) )
2114  return( FALSE ); /* PGP format, certificate */
2116  return( FALSE ); /* Datasize, certificate, externally-suppl.hash */
2117  return( envelopeSign( ENVELOPE_TESTDATA, ENVELOPE_TESTDATA_SIZE, "env_csg", KEYFILE_X509, TRUE, FALSE, TRUE, CRYPT_FORMAT_CRYPTLIB ) );
2118  } /* Externally-supplied key, to test isolation of sig.check key */
2119 
2120 static int envelopeAlgoSign( const char *dumpFileName,
2121  const CRYPT_ALGO_TYPE cryptAlgo )
2122  {
2123  CRYPT_ENVELOPE cryptEnvelope;
2124  CRYPT_CONTEXT sigKey, sigCheckKey;
2125  const char *algoName = \
2126  ( cryptAlgo == CRYPT_ALGO_RSA ) ? "RSA" : \
2127  ( cryptAlgo == CRYPT_ALGO_DSA ) ? "DSA" : \
2128  ( cryptAlgo == CRYPT_ALGO_ECDSA ) ? "ECDSA" : "<Unknown>";
2129  int count;
2130 
2131  printf( "Testing %s signed enveloping...\n", algoName );
2132 
2133  /* Create the en/decryption contexts */
2134  switch( cryptAlgo )
2135  {
2136  case CRYPT_ALGO_RSA:
2137  if( !loadRSAContexts( CRYPT_UNUSED, &sigCheckKey, &sigKey ) )
2138  return( FALSE );
2139  break;
2140 
2141  case CRYPT_ALGO_DSA:
2142  if( !loadDSAContexts( CRYPT_UNUSED, &sigKey, &sigCheckKey ) )
2143  return( FALSE );
2144  break;
2145 
2146  case CRYPT_ALGO_ECDSA:
2147  if( !loadECDSAContexts( &sigKey, &sigCheckKey ) )
2148  return( FALSE );
2149  break;
2150 
2151  default:
2152  printf( "Unknown signature algorithm %d, line %d.\n",
2153  cryptAlgo, __LINE__ );
2154  return( FALSE );
2155  }
2156 
2157  /* Create the envelope, push in the signing key and the data to sign,
2158  pop the enveloped result, and destroy the envelope */
2159  if( !createEnvelope( &cryptEnvelope, CRYPT_FORMAT_CRYPTLIB ) )
2160  return( FALSE );
2161  if( !addEnvInfoNumeric( cryptEnvelope, CRYPT_ENVINFO_SIGNATURE,
2162  sigKey ) )
2163  return( FALSE );
2164  cryptDestroyContext( sigKey );
2165  cryptSetAttribute( cryptEnvelope, CRYPT_ENVINFO_DATASIZE,
2167  count = pushData( cryptEnvelope, ENVELOPE_TESTDATA,
2168  ENVELOPE_TESTDATA_SIZE, NULL, 0 );
2169  if( cryptStatusError( count ) )
2170  return( FALSE );
2171  count = popData( cryptEnvelope, globalBuffer, BUFFER_SIZE );
2172  if( cryptStatusError( count ) )
2173  return( FALSE );
2174  if( !destroyEnvelope( cryptEnvelope ) )
2175  return( FALSE );
2176 
2177  /* Tell them what happened */
2178  printf( "%s-signed data has size %d bytes.\n", algoName, count );
2179  debugDump( dumpFileName, globalBuffer, count );
2180 
2181  /* De-envelope the data and make sure that the result matches what we
2182  pushed */
2183  if( !createDeenvelope( &cryptEnvelope ) )
2184  return( FALSE );
2185  count = pushData( cryptEnvelope, globalBuffer, count, NULL, 0 );
2186  if( !cryptStatusError( count ) )
2187  count = popData( cryptEnvelope, globalBuffer, BUFFER_SIZE );
2188  if( cryptStatusError( count ) )
2189  return( FALSE );
2190  if( !getSigCheckResult( cryptEnvelope, sigCheckKey, TRUE, FALSE ) )
2191  return( FALSE );
2192  cryptDestroyContext( sigCheckKey );
2193  if( !destroyEnvelope( cryptEnvelope ) )
2194  return( FALSE );
2195  if( count != ENVELOPE_TESTDATA_SIZE || \
2196  memcmp( globalBuffer, ENVELOPE_TESTDATA, ENVELOPE_TESTDATA_SIZE ) )
2197  {
2198  puts( "De-enveloped data != original data." );
2199  return( FALSE );
2200  }
2201 
2202  /* Clean up */
2203  puts( "Enveloping of signed data succeeded.\n" );
2204  return( TRUE );
2205  }
2206 
2207 int testEnvelopeSignAlgo( void )
2208  {
2209  if( !envelopeAlgoSign( "env_sig_rsa", CRYPT_ALGO_RSA ) )
2210  return( FALSE );
2211  if( !envelopeAlgoSign( "env_sig_dsa", CRYPT_ALGO_DSA ) )
2212  return( FALSE );
2214  !envelopeAlgoSign( "env_sig_ecc", CRYPT_ALGO_ECDSA ) )
2215  return( FALSE );
2216  return( TRUE );
2217  }
2218 
2219 /* Test signed envelope with forced envelope buffer overflow */
2220 
2221 static int envelopeSignOverflow( const void *data, const int dataLength,
2222  const char *dumpFileName,
2223  const CRYPT_FORMAT_TYPE formatType,
2224  const char *description )
2225  {
2226  CRYPT_ENVELOPE cryptEnvelope;
2228  BYTE localBuffer[ 8192 + 4096 ];
2229  const BOOLEAN forceOverflow = ( dataLength <= 8192 ) ? TRUE : FALSE;
2230  int localBufPos, bytesIn, bytesOut, status;
2231 
2232  if( !keyReadOK )
2233  {
2234  puts( "Couldn't find key files, skipping test of signed "
2235  "enveloping..." );
2236  return( TRUE );
2237  }
2238  printf( "Testing %ssigned enveloping with forced overflow in %s...\n",
2239  ( formatType == CRYPT_FORMAT_PGP ) ? "PGP " : \
2240  ( formatType == CRYPT_FORMAT_SMIME ) ? "S/MIME " : "",
2241  description );
2242 
2243  /* Get the private key */
2244  status = getPrivateKey( &cryptContext, USER_PRIVKEY_FILE,
2246  if( cryptStatusError( status ) )
2247  {
2248  printf( "Read of private key from key file failed, cannot test "
2249  "enveloping, line %d.\n", __LINE__ );
2250  return( FALSE );
2251  }
2252 
2253  /* Create the envelope and push in the signing key and any extra
2254  information */
2255  if( !createEnvelope( &cryptEnvelope, formatType ) )
2256  return( FALSE );
2257  if( !addEnvInfoNumeric( cryptEnvelope, CRYPT_ENVINFO_SIGNATURE,
2258  cryptContext ) )
2259  return( FALSE );
2260  cryptDestroyContext( cryptContext );
2261  status = cryptSetAttribute( cryptEnvelope, CRYPT_ENVINFO_DATASIZE,
2262  dataLength );
2263  if( cryptStatusOK( status ) && forceOverflow )
2264  {
2265  /* Set an artificially-small buffer to force an overflow */
2266  status = cryptSetAttribute( cryptEnvelope, CRYPT_ATTRIBUTE_BUFFERSIZE,
2267  8192 );
2268  }
2269  if( cryptStatusError( status ) )
2270  {
2271  printf( "Couldn't set envelope parameters to force overflow, line "
2272  "%d.\n", __LINE__ );
2273  return( FALSE );
2274  }
2275 
2276  /* Push in the data to sign. Since we're forcing an overflow, we can't
2277  do this via the usual pushData() but have to do it manually to handle
2278  the restart once the overflow occurs */
2279  status = cryptPushData( cryptEnvelope, data, dataLength, &bytesIn );
2280  if( cryptStatusError( status ) || bytesIn != dataLength )
2281  {
2282  printf( "cryptPushData() failed with status %d, copied %d of %d "
2283  "bytes, line %d.\n", status, bytesIn, dataLength, __LINE__ );
2284  return( FALSE );
2285  }
2286  status = cryptFlushData( cryptEnvelope );
2287  if( forceOverflow && status != CRYPT_ERROR_OVERFLOW )
2288  {
2289  printf( "cryptFlushData() returned status %d, should have been "
2290  "CRYPT_ERROR_OVERFLOW,\n line %d.\n", status, __LINE__ );
2291  return( FALSE );
2292  }
2293  status = cryptPopData( cryptEnvelope, localBuffer, 8192 + 4096,
2294  &bytesOut );
2295  if( cryptStatusError( status ) )
2296  {
2297  printf( "cryptPopData() #1 failed with status %d, line %d.\n",
2298  status, __LINE__ );
2299  return( FALSE );
2300  }
2301  localBufPos = bytesOut;
2302  status = cryptFlushData( cryptEnvelope );
2303  if( cryptStatusError( status ) )
2304  {
2305  printf( "cryptFlushData() failed with error code %d, line %d.\n",
2306  status, __LINE__ );
2307  printErrorAttributeInfo( cryptEnvelope );
2308  return( FALSE );
2309  }
2310  status = cryptPopData( cryptEnvelope, localBuffer + localBufPos,
2311  8192 + 4096 - localBufPos, &bytesOut );
2312  if( cryptStatusError( status ) )
2313  {
2314  printf( "cryptPopData() #2 failed with status %d, line %d.\n",
2315  status, __LINE__ );
2316  return( FALSE );
2317  }
2318  localBufPos += bytesOut;
2319  if( !destroyEnvelope( cryptEnvelope ) )
2320  return( FALSE );
2321 
2322  /* Tell them what happened */
2323  printf( "Enveloped data has size %d bytes.\n", localBufPos );
2324  debugDump( dumpFileName, localBuffer, localBufPos );
2325 
2326  /* De-envelope the data and make sure that the result matches what we
2327  pushed */
2328  bytesOut = envelopeSigCheck( localBuffer, localBufPos, CRYPT_UNUSED,
2330  formatType );
2331  if( bytesOut <= 0 )
2332  return( FALSE );
2333  if( bytesOut != dataLength || memcmp( localBuffer, data, dataLength ) )
2334  {
2335  puts( "De-enveloped data != original data." );
2336  return( FALSE );
2337  }
2338 
2339  /* Clean up */
2340  puts( "Enveloping of signed data succeeded.\n" );
2341  return( TRUE );
2342  }
2343 
2344 int testEnvelopeSignOverflow( void )
2345  {
2346  BYTE buffer[ 8192 + 1024 ];
2347 
2348  /* Push in just the right amount of data to force an overflow when we
2349  generate the signature, to check overflow handling in the enveloping
2350  code.
2351 
2352  For PGP it's almost impossible to invoke overflow handling since the
2353  enveloping code is set up to either emit the signature directly into
2354  the buffer or, via an over-conservative estimation of buffer space,
2355  ensure that the user leaves enough space in the buffer for the entire
2356  sig. For an estimated space requirement of 256 bytes, 8192 - 280
2357  will force the sig into the auxBuffer, but since this is an over-
2358  conservative estimate it'll then be flushed straight into the
2359  envelope buffer. The only way to actually force overflow handling
2360  would be to use the longest possible key size and a certificate with
2361  a large issuerAndSerialNumber.
2362 
2363  (In addition to the envelope buffer-overflow check, we also try
2364  enveloping data with a length at the boundary where PGP switches from
2365  2-byte to 4-byte lengths, 8384 bytes, to verify that this works OK).
2366 
2367  For CMS, we can cause an overflow in one of two locations. The first,
2368  with 8192 - 1152 bytes of data, causes an overflow when emitting the
2369  signing certs. This is fairly straightforward, the enveloping code
2370  always requires enough room for the signing certs, so all that happens
2371  is that the user pops some data and tries again.
2372 
2373  The second overflow is with 8192 - 1280 bytes of data, which causes an
2374  overflow on signing */
2375  memset( buffer, '*', 8192 + 1024 );
2376  if( !envelopeSignOverflow( buffer, 8192 - 280, "env_sigo.pgp", CRYPT_FORMAT_PGP, "signature" ) )
2377  return( FALSE ); /* PGP format, raw key */
2378  if( !envelopeSignOverflow( buffer, 8384 - 6, "env_sigo2.pgp", CRYPT_FORMAT_PGP, "seg.boundary" ) )
2379  return( FALSE ); /* PGP format, raw key */
2380  if( !envelopeSignOverflow( buffer, 8192 - 1152, "env_csgo1", CRYPT_FORMAT_SMIME, "signing certs" ) )
2381  return( FALSE ); /* Datasize, certificate, S/MIME semantics */
2382  return( envelopeSignOverflow( buffer, 8192 - 1280, "env_csgo2", CRYPT_FORMAT_SMIME, "signature" ) );
2383  } /* Datasize, certificate, S/MIME semantics */
2384 
2385 /* Test authenticated (MACd) enveloping */
2386 
2387 static int envelopeAuthent( const void *data, const int dataLength,
2388  const BOOLEAN useAuthEnc,
2389  const BOOLEAN useDatasize,
2390  const int corruptDataLocation )
2391  {
2392  CRYPT_ENVELOPE cryptEnvelope;
2393  BOOLEAN corruptionDetected = FALSE;
2394  int count, integrityLevel;
2395 
2396  printf( "Testing authenticated%s enveloping",
2397  useAuthEnc ? "+encrypted" : "" );
2398  if( useDatasize )
2399  printf( " with datasize hint" );
2400  puts( "..." );
2401 
2402  /* Create the envelope and push in the password after telling the
2403  enveloping code that we want to MAC rather than encrypt */
2404  if( !createEnvelope( &cryptEnvelope, CRYPT_FORMAT_CRYPTLIB ) )
2405  return( FALSE );
2406  if( !addEnvInfoNumeric( cryptEnvelope, CRYPT_ENVINFO_INTEGRITY,
2407  useAuthEnc ? CRYPT_INTEGRITY_FULL : \
2409  !addEnvInfoString( cryptEnvelope, CRYPT_ENVINFO_PASSWORD,
2411  return( FALSE );
2412 
2413  /* Push in the data, pop the enveloped result, and destroy the
2414  envelope */
2415  if( useDatasize )
2416  cryptSetAttribute( cryptEnvelope, CRYPT_ENVINFO_DATASIZE,
2417  dataLength );
2418  count = pushData( cryptEnvelope, data, dataLength, NULL, 0 );
2419  if( cryptStatusError( count ) )
2420  return( FALSE );
2421  count = popData( cryptEnvelope, globalBuffer, BUFFER_SIZE );
2422  if( cryptStatusError( count ) )
2423  return( FALSE );
2424  if( !destroyEnvelope( cryptEnvelope ) )
2425  return( FALSE );
2426 
2427  /* Tell them what happened */
2428  printf( "Enveloped data has size %d bytes.\n", count );
2429  debugDump( useAuthEnc ? "env_authenc" : \
2430  useDatasize ? "env_mac" : "env_macn", globalBuffer, count );
2431 
2432  /* If we're testing sig.verification, corrupt one of the payload bytes.
2433  This is a bit tricky because we have to hardcode the location of the
2434  payload byte, if we change the format at (for example by using a
2435  different algorithm somewhere) then this location will change */
2436  if( corruptDataLocation > 0 )
2437  globalBuffer[ corruptDataLocation ]++;
2438 
2439  /* Create the envelope */
2440  if( !createDeenvelope( &cryptEnvelope ) )
2441  return( FALSE );
2442 
2443  /* Push in the data */
2444  count = pushData( cryptEnvelope, globalBuffer, count,
2446  if( cryptStatusError( count ) )
2447  {
2448  if( corruptDataLocation && count == CRYPT_ERROR_SIGNATURE )
2449  {
2450  puts( " (This is an expected result since this test verifies "
2451  "handling of\n corrupted authenticated data)." );
2452  corruptionDetected = TRUE;
2453  }
2454  else
2455  return( FALSE );
2456  }
2457  else
2458  {
2459  count = popData( cryptEnvelope, globalBuffer, BUFFER_SIZE );
2460  if( cryptStatusError( count ) )
2461  return( FALSE );
2462  }
2463 
2464  /* Make sure that the envelope is reported as being authenticated */
2465  if( cryptStatusError( \
2466  cryptGetAttribute( cryptEnvelope, CRYPT_ENVINFO_INTEGRITY,
2467  &integrityLevel ) ) || \
2468  integrityLevel <= CRYPT_INTEGRITY_NONE )
2469  {
2470  printf( "Integrity-protected envelope is reported as having no "
2471  "integrity protection,\n line %d.\n", __LINE__ );
2472  return( FALSE );
2473  }
2474 
2475  /* Determine the result of the MAC check */
2476  if( !getSigCheckResult( cryptEnvelope, CRYPT_UNUSED, FALSE, TRUE ) && \
2477  corruptDataLocation == 0 )
2478  return( FALSE );
2479  if( !destroyEnvelope( cryptEnvelope ) )
2480  return( FALSE );
2481 
2482  /* Make sure that we got what we were expecting */
2483  if( corruptDataLocation == 0 )
2484  {
2485  if( count != dataLength || memcmp( globalBuffer, data, dataLength ) )
2486  {
2487  puts( "De-enveloped data != original data." );
2488  return( FALSE );
2489  }
2490  }
2491  else
2492  {
2493  if( !corruptionDetected )
2494  {
2495  puts( "Corruption of encrypted data wasn't detected." );
2496  return( FALSE );
2497  }
2498  }
2499 
2500  /* Clean up */
2501  puts( "Enveloping of authenticated data succeeded.\n" );
2502  return( TRUE );
2503  }
2504 
2505 int testEnvelopeAuthenticate( void )
2506  {
2507  if( !envelopeAuthent( ENVELOPE_TESTDATA, ENVELOPE_TESTDATA_SIZE, FALSE, FALSE, FALSE ) )
2508  return( FALSE ); /* Indefinite length */
2509  if( !envelopeAuthent( ENVELOPE_TESTDATA, ENVELOPE_TESTDATA_SIZE, FALSE, TRUE, FALSE ) )
2510  return( FALSE ); /* Datasize */
2511  return( envelopeAuthent( ENVELOPE_TESTDATA, ENVELOPE_TESTDATA_SIZE, FALSE, TRUE, 175 ) );
2512  } /* Datasize, corrupt data to check sig.verification */
2513 
2514 int testEnvelopeAuthEnc( void )
2515  {
2516  if( !envelopeAuthent( ENVELOPE_TESTDATA, ENVELOPE_TESTDATA_SIZE, TRUE, FALSE, FALSE ) )
2517  return( FALSE ); /* Indefinite length */
2518  if( !envelopeAuthent( ENVELOPE_TESTDATA, ENVELOPE_TESTDATA_SIZE, TRUE, TRUE, FALSE ) )
2519  return( FALSE ); /* Datasize */
2520  if( !envelopeAuthent( ENVELOPE_TESTDATA, ENVELOPE_TESTDATA_SIZE, TRUE, TRUE, 192 ) )
2521  return( FALSE ); /* Datasize, corrupt payload data to check sig.verification */
2522  return( envelopeAuthent( ENVELOPE_TESTDATA, ENVELOPE_TESTDATA_SIZE, TRUE, TRUE, 170 ) );
2523  } /* Datasize, corrupt metadata to check sig.verification */
2524 
2525 /****************************************************************************
2526 * *
2527 * CMS Enveloping Test Routines *
2528 * *
2529 ****************************************************************************/
2530 
2531 /* Test CMS signature generation/checking */
2532 
2533 static int displaySigResult( const CRYPT_ENVELOPE cryptEnvelope,
2534  const CRYPT_CONTEXT sigCheckContext,
2535  const BOOLEAN mustHaveAttributes,
2536  const BOOLEAN firstSig )
2537  {
2538  CRYPT_CERTIFICATE signerInfo;
2539  BOOLEAN sigStatus;
2540  int status;
2541 
2542  /* Determine the result of the signature check. We only display the
2543  attributes for the first sig since this operation walks the attribute
2544  list,which moves the attribute cursor */
2545  sigStatus = getSigCheckResult( cryptEnvelope, sigCheckContext,
2546  firstSig, FALSE );
2547  if( sigCheckContext != CRYPT_UNUSED )
2548  {
2549  /* If the sig.check key is provided externally (which in practice we
2550  only do for PGP sigs), there's no signer info or extra data
2551  present */
2552  return( sigStatus );
2553  }
2554 
2555  /* Report on the signer and signature info. We continue even if the sig.
2556  status is bad since we can still try and display signing info even if
2557  the check fails */
2558  status = cryptGetAttribute( cryptEnvelope, CRYPT_ENVINFO_SIGNATURE,
2559  &signerInfo );
2560  if( cryptStatusError( status ) && sigStatus )
2561  {
2562  printf( "Couldn't retrieve signer information from CMS signature, "
2563  "status = %d, line %d.\n", status, __LINE__ );
2564  return( FALSE );
2565  }
2566  if( cryptStatusOK( status ) )
2567  {
2568  puts( "Signer information is:" );
2569  if( !printCertInfo( signerInfo ) )
2570  return( FALSE );
2571  cryptDestroyCert( signerInfo );
2572  }
2573  status = cryptGetAttribute( cryptEnvelope,
2574  CRYPT_ENVINFO_SIGNATURE_EXTRADATA, &signerInfo );
2575  if( cryptStatusError( status ) && sigStatus && \
2576  ( mustHaveAttributes || status != CRYPT_ERROR_NOTFOUND ) )
2577  {
2578  printf( "Couldn't retrieve signature information from CMS signature, "
2579  "status = %d, line %d.\n", status, __LINE__ );
2580  return( FALSE );
2581  }
2582  if( cryptStatusOK( status ) )
2583  {
2584  puts( "Signature information is:" );
2585  if( !printCertInfo( signerInfo ) )
2586  return( FALSE );
2587  cryptDestroyCert( signerInfo );
2588  }
2589 
2590  return( sigStatus );
2591  }
2592 
2593 static int cmsEnvelopeSigCheck( const void *signedData,
2594  const int signedDataLength,
2595  const CRYPT_CONTEXT sigCheckContext,
2596  const CRYPT_CONTEXT hashContext,
2597  const BOOLEAN detachedSig,
2598  const BOOLEAN hasTimestamp,
2599  const BOOLEAN checkData,
2600  const BOOLEAN mustHaveAttributes,
2601  const BOOLEAN checkWrongKey )
2602  {
2603  CRYPT_ENVELOPE cryptEnvelope;
2604  int count, status;
2605 
2606  /* Create the (de-)envelope and push in the data. Since this is a CMS
2607  signature that carries its certs with it, there's no need to push in
2608  a sig.check keyset. If it has a detached sig, we need to push two
2609  lots of data, first the signature to set the envelope state, then the
2610  data, however if the hash is being supplied externally we just set the
2611  hash attribute. In addition if it's a detached sig, there's nothing
2612  to be unwrapped so we don't pop any data */
2613  if( !createDeenvelope( &cryptEnvelope ) )
2614  return( FALSE );
2615  if( detachedSig && hashContext != CRYPT_UNUSED )
2616  {
2617  /* The hash value is being supplied externally, add it to the
2618  envelope before we add the signature data */
2619  status = cryptSetAttribute( cryptEnvelope, CRYPT_ENVINFO_HASH,
2620  hashContext );
2621  if( cryptStatusError( status ) )
2622  {
2623  printf( "Couldn't add externally-generated hash value to "
2624  "envelope, status %d, line %d.\n", status, __LINE__ );
2625  return( FALSE );
2626  }
2627  }
2628  count = pushData( cryptEnvelope, signedData, signedDataLength, NULL, 0 );
2629  if( count == CRYPT_ERROR_NOTAVAIL && \
2630  !( detachedSig || hasTimestamp || checkData ) )
2631  {
2632  /* Some old signed data uses deprecated or now-broken algorithms
2633  which will produce a CRYPT_ERROR_NOTAVAIL if we try and verify
2634  the signature, treat this as a special case */
2635  puts( "Warning: The hash/signature algorithm required to verify "
2636  "the signed data\n isn't enabled in this build of "
2637  "cryptlib, can't verify the\n signature." );
2638  if( !destroyEnvelope( cryptEnvelope ) )
2639  return( FALSE );
2640  return( TRUE );
2641  }
2642  if( !cryptStatusError( count ) )
2643  {
2644  if( detachedSig )
2645  {
2646  if( hashContext == CRYPT_UNUSED )
2647  count = pushData( cryptEnvelope, ENVELOPE_TESTDATA,
2648  ENVELOPE_TESTDATA_SIZE, NULL, 0 );
2649  }
2650  else
2651  count = popData( cryptEnvelope, globalBuffer, BUFFER_SIZE );
2652  }
2653  if( cryptStatusError( count ) )
2654  return( FALSE );
2655 
2656  /* If we're checking for the ability to reject an incorrect key, fetch
2657  a bogus signature key and try and add that */
2658  if( checkWrongKey )
2659  {
2660  CRYPT_CERTIFICATE cryptWrongCert;
2661 
2662  status = getPublicKey( &cryptWrongCert, DUAL_PRIVKEY_FILE,
2664  if( cryptStatusError( status ) )
2665  return( FALSE );
2666  status = cryptSetAttribute( cryptEnvelope, CRYPT_ENVINFO_SIGNATURE,
2667  cryptWrongCert );
2668  cryptDestroyCert( cryptWrongCert );
2669  if( status != CRYPT_ERROR_WRONGKEY )
2670  {
2671  printf( "Use of incorrect key wasn't detected, got %d, should "
2672  "have been %d, line %d.\n", status,
2673  CRYPT_ERROR_WRONGKEY, __LINE__ );
2674  return( FALSE );
2675  }
2676  }
2677 
2678  /* Display the details of the envelope signature and check whether
2679  there's more information such as a timestamp or a second signature
2680  present */
2681  status = displaySigResult( cryptEnvelope, sigCheckContext,
2682  mustHaveAttributes, TRUE );
2683  if( status == TRUE && hasTimestamp )
2684  {
2685  CRYPT_ENVELOPE cryptTimestamp;
2686  int contentType;
2687 
2688  /* Try and get the timestamp info. We can't safely use
2689  displaySigResult() on this because many timestamps are stripped-
2690  down minimal-size CMS messages with no additional sig-checking
2691  info present, so we just read the CMS content-type to make sure
2692  that everything's OK */
2693  printf( "Envelope contains a timestamp..." );
2694  status = cryptGetAttribute( cryptEnvelope, CRYPT_ENVINFO_TIMESTAMP,
2695  &cryptTimestamp );
2696  if( cryptStatusError( status ) )
2697  {
2698  printf( "\nCouldn't read timestamp from envelope, status %d, "
2699  "line %d.\n", status, __LINE__ );
2700  return( FALSE );
2701  }
2702  status = cryptGetAttribute( cryptTimestamp,
2703  CRYPT_ENVINFO_CONTENTTYPE, &contentType );
2704  if( cryptStatusError( status ) || \
2705  contentType != CRYPT_CONTENT_TSTINFO )
2706  {
2707  printf( "\nTimestamp data envelope doesn't appear to contain a "
2708  "timestamp, line %d.\n", __LINE__ );
2709  return( FALSE );
2710  }
2711  printf( " timestamp data appears OK.\n" );
2712  cryptDestroyEnvelope( cryptTimestamp );
2713  status = TRUE;
2714  }
2715  if( status == TRUE && cryptStatusOK( \
2717  CRYPT_CURSOR_NEXT ) ) )
2718  {
2719  puts( "Data has a second signature:" );
2720  status = displaySigResult( cryptEnvelope, CRYPT_UNUSED,
2721  mustHaveAttributes, FALSE );
2722  }
2723  if( status == TRUE && cryptStatusOK( \
2725  CRYPT_CURSOR_NEXT ) ) )
2726  {
2727  /* We can have two, but not three */
2728  puts( "Data appears to have (nonexistent) third signature." );
2729  return( FALSE );
2730  }
2731 
2732  /* Make sure that the result matches what we pushed */
2733  if( !detachedSig && checkData && ( count != ENVELOPE_TESTDATA_SIZE || \
2734  memcmp( globalBuffer, ENVELOPE_TESTDATA, ENVELOPE_TESTDATA_SIZE ) ) )
2735  {
2736  puts( "De-enveloped data != original data." );
2737  return( FALSE );
2738  }
2739 
2740  /* Clean up */
2741  if( !destroyEnvelope( cryptEnvelope ) )
2742  return( FALSE );
2743  return( status );
2744  }
2745 
2746 static int cmsEnvelopeSign( const BOOLEAN useDatasize,
2747  const BOOLEAN useAttributes, const BOOLEAN useExtAttributes,
2748  const BOOLEAN detachedSig, const BOOLEAN useExternalHash,
2749  const BOOLEAN useTimestamp, const BOOLEAN useNonDataContent,
2750  const BOOLEAN dualSig, const CRYPT_CONTEXT externalSignContext,
2751  const CRYPT_FORMAT_TYPE formatType )
2752  {
2753  CRYPT_ENVELOPE cryptEnvelope;
2754  CRYPT_CONTEXT cryptContext, cryptContext2, hashContext = CRYPT_UNUSED;
2755  BOOLEAN isPGP = ( formatType == CRYPT_FORMAT_PGP ) ? TRUE : FALSE;
2756  int count, status = CRYPT_OK;
2757 
2758  if( !keyReadOK )
2759  {
2760  puts( "Couldn't find key files, skipping test of CMS signed "
2761  "enveloping..." );
2762  return( TRUE );
2763  }
2764  printf( "Testing %s %s%s", isPGP ? "PGP" : "CMS",
2765  useExtAttributes ? "extended " : "",
2766  detachedSig ? "detached signature" : \
2767  dualSig ? "dual signature" : "signed enveloping" );
2768  if( useNonDataContent )
2769  printf( " of non-data content" );
2770  if( useExternalHash )
2771  printf( " with externally-supplied hash" );
2772  if( !useAttributes )
2773  printf( " without signing attributes" );
2774  if( useDatasize && \
2775  !( useNonDataContent || useAttributes || useExtAttributes || \
2776  detachedSig || useTimestamp ) )
2777  {
2778  /* Keep the amount of stuff being printed down */
2779  printf( " with datasize hint" );
2780  }
2781  if( useTimestamp )
2782  printf( " and timestamp" );
2783  puts( "..." );
2784 
2785  /* Get the private key. If we're applying two signatures, we also get
2786  a second signing key. Since the dual-key file test has created a
2787  second signing key, we use that as the most convenient one */
2788  if( externalSignContext != CRYPT_UNUSED )
2789  cryptContext = externalSignContext;
2790  else
2791  {
2792  status = getPrivateKey( &cryptContext, USER_PRIVKEY_FILE,
2794  if( cryptStatusError( status ) )
2795  {
2796  puts( "Read of private key from key file failed, cannot test "
2797  "CMS enveloping." );
2798  return( FALSE );
2799  }
2800  }
2801  if( dualSig )
2802  {
2803  status = getPrivateKey( &cryptContext2, DUAL_PRIVKEY_FILE,
2805  if( cryptStatusError( status ) )
2806  {
2807  puts( "Read of private key from key file failed, cannot test "
2808  "CMS enveloping." );
2809  return( FALSE );
2810  }
2811  }
2812 
2813  /* Create the CMS envelope, push in the signing key(s) and data, pop the
2814  enveloped result, and destroy the envelope */
2815  if( !createEnvelope( &cryptEnvelope, formatType ) || \
2816  !addEnvInfoNumeric( cryptEnvelope, CRYPT_ENVINFO_SIGNATURE,
2817  cryptContext ) )
2818  return( FALSE );
2819  if( dualSig &&
2820  !addEnvInfoNumeric( cryptEnvelope, CRYPT_ENVINFO_SIGNATURE,
2821  cryptContext2 ) )
2822  return( FALSE );
2823  if( ( externalSignContext == CRYPT_UNUSED ) && !isPGP )
2824  cryptDestroyContext( cryptContext );
2825  if( dualSig )
2826  cryptDestroyContext( cryptContext2 );
2827  if( useNonDataContent )
2828  {
2829  /* Test non-data content type w.automatic attribute handling */
2830  status = cryptSetAttribute( cryptEnvelope, CRYPT_ENVINFO_CONTENTTYPE,
2832  }
2833  if( cryptStatusOK( status ) && useDatasize )
2834  status = cryptSetAttribute( cryptEnvelope, CRYPT_ENVINFO_DATASIZE,
2836  if( cryptStatusOK( status ) && useExtAttributes )
2837  {
2838  /* We have to be careful when setting CMS attributes because most
2839  are never used by anything so they're only available of use of
2840  obscure attributes is enabled (unfortunately there aren't
2841  actually any attributes that are available for this, but the
2842  functionality is tested by the added-by-default attributes such
2843  as the signing time) */
2844 #ifdef USE_CMS_OBSCURE
2845  CRYPT_CERTIFICATE cmsAttributes;
2846 
2847  /* Add an ESS security label and signing description as signing
2848  attributes */
2849  status = cryptCreateCert( &cmsAttributes, CRYPT_UNUSED,
2851  if( cryptStatusError( status ) )
2852  return( FALSE );
2853  status = cryptSetAttributeString( cmsAttributes,
2855  TEXT( "1 3 6 1 4 1 9999 1" ),
2856  paramStrlen( TEXT( "1 3 6 1 4 1 9999 1" ) ) );
2857  if( cryptStatusOK( status ) )
2858  status = cryptSetAttribute( cmsAttributes,
2861  if( cryptStatusOK( status ) )
2862  status = cryptSetAttributeString( cmsAttributes,
2864  TEXT( "1 3 6 1 4 1 9999 2" ),
2865  paramStrlen( TEXT( "1 3 6 1 4 1 9999 2" ) ) );
2866  if( cryptStatusOK( status ) )
2867  status = cryptSetAttributeString( cmsAttributes,
2869  "\x04\x04\x01\x02\x03\x04", 6 );
2870  if( cryptStatusOK( status ) )
2871  status = cryptSetAttributeString( cmsAttributes,
2873  "This signature isn't worth the paper it's not "
2874  "printed on", 56 );
2875  if( cryptStatusOK( status ) )
2876  status = cryptSetAttribute( cryptEnvelope,
2877  CRYPT_ENVINFO_SIGNATURE_EXTRADATA, cmsAttributes );
2878  cryptDestroyCert( cmsAttributes );
2879 #endif /* USE_CMS_OBSCURE */
2880  }
2881  if( cryptStatusOK( status ) && detachedSig )
2882  status = cryptSetAttribute( cryptEnvelope,
2884  if( cryptStatusOK( status ) && !useAttributes )
2885  status = cryptSetAttribute( CRYPT_UNUSED,
2887  if( cryptStatusOK( status ) && useTimestamp )
2888  {
2889  CRYPT_SESSION cryptSession;
2890 
2891  /* Create the TSP session, add the TSA URL, and add it to the
2892  envelope */
2893  status = cryptCreateSession( &cryptSession, CRYPT_UNUSED,
2895  if( status == CRYPT_ERROR_PARAM3 ) /* TSP session access not available */
2896  return( CRYPT_ERROR_NOTAVAIL );
2897  status = cryptSetAttributeString( cryptSession,
2901  if( cryptStatusError( status ) )
2902  return( attrErrorExit( cryptSession, "cryptSetAttributeString()",
2903  status, __LINE__ ) );
2904  status = cryptSetAttribute( cryptEnvelope, CRYPT_ENVINFO_TIMESTAMP,
2905  cryptSession );
2906  cryptDestroySession( cryptSession );
2907  }
2908  if( cryptStatusError( status ) )
2909  {
2910  printf( "cryptSetAttribute() failed with error code %d, line %d.\n",
2911  status, __LINE__ );
2912  return( FALSE );
2913  }
2914  count = pushData( cryptEnvelope, ENVELOPE_TESTDATA,
2915  ENVELOPE_TESTDATA_SIZE, NULL, 0 );
2916  if( !useAttributes )
2917  {
2918  /* Restore the default attributes setting */
2920  TRUE );
2921  }
2922  if( cryptStatusError( count ) )
2923  {
2924  /* The timestamping can fail for a wide range of (non-fatal) reasons,
2925  typically either because this build doesn't have networking
2926  enabled or because the TSA can't be contacted, so we don't treat
2927  this one as a fatal error */
2928  if( useTimestamp )
2929  {
2930  puts( "Envelope timestamping failed due to problems talking to "
2931  "TSA, this is a non-\ncritical problem. Continuing...\n" );
2932  cryptDestroyEnvelope( cryptEnvelope );
2933  return( TRUE );
2934  }
2935  return( FALSE );
2936  }
2937  count = popData( cryptEnvelope, globalBuffer, BUFFER_SIZE );
2938  if( cryptStatusError( count ) )
2939  return( FALSE );
2940  if( !destroyEnvelope( cryptEnvelope ) )
2941  return( FALSE );
2942 
2943  /* Tell them what happened */
2944  printf( "%s %s has size %d bytes.\n", isPGP ? "PGP" : "CMS",
2945  ( detachedSig ) ? "detached signature" : "signed data",
2946  count );
2947  debugDump( detachedSig ?
2948  ( !isPGP ? \
2949  ( useDatasize ? "smi_dsg" : "smi_dsgn" ) : \
2950  "pgp_dsg.pgp" ) : \
2951  useExtAttributes ? \
2952  ( useDatasize ? "smi_esg" : "smi_esgn" ) : \
2953  useTimestamp ? \
2954  ( useDatasize ? "smi_tsg" : "smi_tsgn" ) : \
2955  useNonDataContent ? \
2956  ( useDatasize ? "smi_ndc" : "smi_ndcn" ) : \
2957  dualSig ? \
2958  ( useDatasize ? "smi_2sg" : "smi_n2sg" ) : \
2959  useDatasize ? "smi_sig" : "smi_sign", globalBuffer, count );
2960 
2961  /* If we're supplying the hash value externally, calculate it now */
2962  if( useExternalHash )
2963  {
2964  status = cryptCreateContext( &hashContext, CRYPT_UNUSED,
2965  CRYPT_ALGO_SHA );
2966  if( cryptStatusOK( status ) )
2967  status = cryptEncrypt( hashContext, ENVELOPE_TESTDATA,
2969  if( cryptStatusOK( status ) && formatType == CRYPT_FORMAT_CMS )
2970  status = cryptEncrypt( hashContext, "", 0 );
2971  if( cryptStatusError( status ) )
2972  {
2973  puts( "Couldn't create external hash of data." );
2974  return( FALSE );
2975  }
2976  }
2977 
2978  /* Make sure that the signature is valid. The somewhat redundant mapping
2979  of useNonDataContent is because we're performing an additional check
2980  of envelope key-handling as part of this particular operation */
2981  status = cmsEnvelopeSigCheck( globalBuffer, count,
2982  isPGP ? cryptContext : CRYPT_UNUSED,
2983  hashContext, detachedSig, FALSE, TRUE,
2984  useAttributes, useNonDataContent ? \
2985  TRUE : FALSE );
2986  if( hashContext != CRYPT_UNUSED )
2987  cryptDestroyContext( hashContext );
2988  if( isPGP )
2989  cryptDestroyContext( cryptContext );
2990  if( status <= 0 )
2991  return( FALSE );
2992 
2993  if( detachedSig )
2994  {
2995  printf( "Creation of %s %sdetached signature %ssucceeded.\n\n",
2996  isPGP ? "PGP" : "CMS", useExtAttributes ? "extended " : "",
2997  ( hashContext != CRYPT_UNUSED ) ? \
2998  "with externally-supplied hash " : "" );
2999  }
3000  else
3001  {
3002  printf( "Enveloping of CMS %s%ssigned data succeeded.\n\n",
3003  useExtAttributes ? "extended " : "",
3004  useTimestamp ? "timestamped " : "" );
3005  }
3006  return( TRUE );
3007  }
3008 
3009 int testCMSEnvelopeSign( void )
3010  {
3011  if( !cmsEnvelopeSign( FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, CRYPT_UNUSED, CRYPT_FORMAT_CMS ) )
3012  return( FALSE ); /* Minimal (no default S/MIME attributes) */
3013  if( !cmsEnvelopeSign( FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, CRYPT_UNUSED, CRYPT_FORMAT_CMS ) )
3014  return( FALSE ); /* Standard (default S/MIME signing attributes) */
3015  if( !cmsEnvelopeSign( TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, CRYPT_UNUSED, CRYPT_FORMAT_CMS ) )
3016  return( FALSE ); /* Datasize and attributes */
3017  if( !cmsEnvelopeSign( FALSE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, CRYPT_UNUSED, CRYPT_FORMAT_CMS ) )
3018  return( FALSE ); /* Extended signing attributes */
3019  if( !cmsEnvelopeSign( TRUE, TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, CRYPT_UNUSED, CRYPT_FORMAT_CMS ) )
3020  return( FALSE ); /* Datasize and extended attributes */
3021  return( cmsEnvelopeSign( TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, CRYPT_UNUSED, CRYPT_FORMAT_CMS ) );
3022  } /* Signing of non-data content */
3023 
3024 int testCMSEnvelopeDualSign( void )
3025  {
3026  return( cmsEnvelopeSign( TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, CRYPT_UNUSED, CRYPT_FORMAT_CMS ) );
3027  /* Standard, with two signatures */
3028  }
3029 
3030 int testCMSEnvelopeDetachedSig( void )
3031  {
3032  if( !cmsEnvelopeSign( FALSE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE, FALSE, CRYPT_UNUSED, CRYPT_FORMAT_CMS ) )
3033  return( FALSE ); /* Detached sig and attributes */
3034  if( !cmsEnvelopeSign( FALSE, TRUE, FALSE, TRUE, TRUE, FALSE, FALSE, FALSE, CRYPT_UNUSED, CRYPT_FORMAT_CMS ) )
3035  return( FALSE ); /* Detached sig, attributes, externally-suppl.hash */
3036  return( cmsEnvelopeSign( TRUE, TRUE, FALSE, TRUE, TRUE, FALSE, FALSE, FALSE, CRYPT_UNUSED, CRYPT_FORMAT_PGP ) );
3037  } /* Detached sig, data size, externally-suppl.hash, PGP format */
3038 
3040  {
3041  return( cmsEnvelopeSign( TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, signContext, CRYPT_FORMAT_CMS ) );
3042  } /* Datasize, attributes, external signing context */
3043 
3044 int testSessionEnvTSP( void )
3045  {
3046  /* This is a pseudo-enveloping test that uses the enveloping
3047  functionality but is called as part of the session tests since full
3048  testing of the TSP handling requires that it be used to timestamp an
3049  S/MIME sig */
3050  return( cmsEnvelopeSign( TRUE, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, CRYPT_UNUSED, CRYPT_FORMAT_CMS ) );
3051  } /* Datasize, attributes, timestamp */
3052 
3053 static int cmsImportSignedData( const char *fileName, const int fileNo )
3054  {
3055  BYTE *bufPtr = globalBuffer;
3056  char msgBuffer[ 128 ];
3057  int count, status;
3058 
3059  /* Read the test data */
3060  count = getFileSize( fileName ) + 10;
3061  if( count >= BUFFER_SIZE )
3062  {
3063  if( ( bufPtr = malloc( count ) ) == NULL )
3064  {
3065  printf( "Couldn't allocate test buffer of %d bytes, line %d.\n",
3066  count, __LINE__ );
3067  return( FALSE );
3068  }
3069  }
3070  sprintf( msgBuffer, "S/MIME SignedData #%d", fileNo );
3071  count = readFileData( fileName, msgBuffer, bufPtr, count );
3072  if( count <= 0 )
3073  {
3074  if( bufPtr != globalBuffer )
3075  free( bufPtr );
3076  return( count );
3077  }
3078 
3079  /* Check the signature on the data */
3080  status = cmsEnvelopeSigCheck( bufPtr, count, CRYPT_UNUSED, CRYPT_UNUSED,
3081  FALSE, FALSE, FALSE,
3082  ( fileNo == 1 ) ? FALSE : TRUE, FALSE );
3083  if( bufPtr != globalBuffer )
3084  free( bufPtr );
3085  if( status )
3086  puts( "S/MIME SignedData import succeeded.\n" );
3087  else
3088  {
3089  /* The AuthentiCode data sig-check fails for some reason */
3090  if( fileNo == 2 )
3091  {
3092  puts( "AuthentiCode SignedData import succeeded but signature "
3093  "couldn't be verified\n due to AuthentiCode special "
3094  "processing requirements.\n" );
3095  }
3096  }
3097  return( status );
3098  }
3099 
3100 /* Test CMS enveloping/de-enveloping */
3101 
3102 static int cmsEnvelopeDecrypt( const void *envelopedData,
3103  const int envelopedDataLength,
3104  const CRYPT_HANDLE externalKeyset,
3105  const C_STR externalPassword,
3106  const BOOLEAN checkDataMatch )
3107  {
3108  CRYPT_ENVELOPE cryptEnvelope;
3109  int count, status;
3110 
3111  /* Create the envelope and push in the decryption keyset */
3112  if( !createDeenvelope( &cryptEnvelope ) )
3113  return( FALSE );
3114  if( externalKeyset != CRYPT_UNUSED )
3115  status = addEnvInfoNumeric( cryptEnvelope,
3116  CRYPT_ENVINFO_KEYSET_DECRYPT, externalKeyset );
3117  else
3118  {
3119  CRYPT_KEYSET cryptKeyset;
3120 
3121  status = cryptKeysetOpen( &cryptKeyset, CRYPT_UNUSED,
3124  if( cryptStatusOK( status ) )
3125  status = addEnvInfoNumeric( cryptEnvelope,
3126  CRYPT_ENVINFO_KEYSET_DECRYPT, cryptKeyset );
3127  cryptKeysetClose( cryptKeyset );
3128  }
3129  if( status <= 0 )
3130  return( FALSE );
3131 
3132  /* Push in the data */
3133  count = pushData( cryptEnvelope, envelopedData, envelopedDataLength,
3134  ( externalPassword == NULL ) ? TEST_PRIVKEY_PASSWORD :
3135  externalPassword, 0 );
3136  if( cryptStatusError( count ) )
3137  return( FALSE );
3138  count = popData( cryptEnvelope, globalBuffer, BUFFER_SIZE );
3139  if( cryptStatusError( count ) )
3140  return( FALSE );
3141  if( !destroyEnvelope( cryptEnvelope ) )
3142  return( FALSE );
3143 
3144  /* If we're not checking for a match of the decrypted data (done when
3145  the data is coming from an external source rather than being
3146  something that we generated ourselves), we're done */
3147  if( !checkDataMatch )
3148  return( TRUE );
3149 
3150  /* Make sure that the result matches what we pushed */
3151  if( count != ENVELOPE_TESTDATA_SIZE || \
3152  memcmp( globalBuffer, ENVELOPE_TESTDATA, ENVELOPE_TESTDATA_SIZE ) )
3153  {
3154  puts( "De-enveloped data != original data." );
3155  return( FALSE );
3156  }
3157 
3158  return( TRUE );
3159  }
3160 
3161 static int cmsEnvelopeCrypt( const char *dumpFileName,
3162  const BOOLEAN useDatasize,
3163  const BOOLEAN useStreamCipher,
3164  const BOOLEAN useLargeBlockCipher,
3165  const BOOLEAN useExternalRecipientKeyset,
3166  const CRYPT_HANDLE externalCryptContext,
3167  const CRYPT_HANDLE externalKeyset,
3168  const C_STR externalPassword,
3169  const C_STR recipientName )
3170  {
3171  CRYPT_ENVELOPE cryptEnvelope;
3173  int count, status;
3174 
3175  if( !keyReadOK )
3176  {
3177  puts( "Couldn't find key files, skipping test of CMS encrypted "
3178  "enveloping..." );
3179  return( TRUE );
3180  }
3181  printf( "Testing CMS public-key encrypted enveloping" );
3182  if( externalKeyset != CRYPT_UNUSED && recipientName != NULL )
3183  {
3184  if( useExternalRecipientKeyset )
3185  printf( " with recipient keys in device" );
3186  else
3187  printf( " with dual encr./signing certs" );
3188  }
3189  else
3190  {
3191  if( useStreamCipher )
3192  printf( " with stream cipher" );
3193  else
3194  {
3195  if( useLargeBlockCipher )
3196  printf( " with large block size cipher" );
3197  else
3198  {
3199  if( useDatasize )
3200  printf( " with datasize hint" );
3201  }
3202  }
3203  }
3204  puts( "..." );
3205 
3206  /* Get the public key. We use assorted variants to make sure that they
3207  all work */
3208  if( externalCryptContext != CRYPT_UNUSED )
3209  {
3210  int cryptAlgo;
3211 
3212  status = cryptGetAttribute( externalCryptContext, CRYPT_CTXINFO_ALGO,
3213  &cryptAlgo );
3214  if( cryptStatusError( status ) )
3215  {
3216  puts( "Couldn't determine algorithm for public key, cannot test "
3217  "CMS enveloping." );
3218  return( FALSE );
3219  }
3220  cryptKey = externalCryptContext;
3221  }
3222  else
3223  {
3224  if( recipientName == NULL )
3225  {
3226  CRYPT_KEYSET cryptKeyset;
3227 
3228  /* No recipient name, get the public key */
3229  status = cryptKeysetOpen( &cryptKeyset, CRYPT_UNUSED,
3232  if( cryptStatusError( status ) )
3233  {
3234  printf( "Recipient keyset open failed with status %d, "
3235  "line %d.\n", status, __LINE__ );
3236  return( FALSE );
3237  }
3238  status = cryptGetPublicKey( cryptKeyset, &cryptKey,
3241  cryptKeysetClose( cryptKeyset );
3242  if( cryptStatusError( status ) )
3243  {
3244  printf( "Read of public key from key file failed with "
3245  "status %d, line %d.\n", status, __LINE__ );
3246  return( FALSE );
3247  }
3248  }
3249  }
3250 
3251  /* Create the envelope, add the public key and originator key if
3252  necessary, push in the data, pop the enveloped result, and destroy
3253  the envelope */
3254  if( !createEnvelope( &cryptEnvelope, CRYPT_FORMAT_CMS ) )
3255  return( FALSE );
3256  if( recipientName != NULL )
3257  {
3258  CRYPT_KEYSET cryptKeyset = externalKeyset;
3259 
3260  /* We're using a recipient name, add the recipient keyset and
3261  recipient name */
3262  if( !useExternalRecipientKeyset )
3263  {
3264  status = cryptKeysetOpen( &cryptKeyset, CRYPT_UNUSED,
3268  if( cryptStatusError( status ) )
3269  {
3270  printf( "Couldn't open key database, status %d, line %d.\n",
3271  status, __LINE__ );
3272  return( FALSE );
3273  }
3274  }
3275  if( !addEnvInfoNumeric( cryptEnvelope, CRYPT_ENVINFO_KEYSET_ENCRYPT,
3276  cryptKeyset ) )
3277  return( FALSE );
3278  if( !useExternalRecipientKeyset )
3279  cryptKeysetClose( cryptKeyset );
3280  if( !addEnvInfoString( cryptEnvelope, CRYPT_ENVINFO_RECIPIENT,
3281  recipientName, paramStrlen( recipientName ) ) )
3282  return( FALSE );
3283  }
3284  else
3285  {
3286  if( !addEnvInfoNumeric( cryptEnvelope, CRYPT_ENVINFO_PUBLICKEY,
3287  cryptKey ) )
3288  return( FALSE );
3289  }
3290  if( externalCryptContext == CRYPT_UNUSED && recipientName == NULL )
3291  cryptDestroyObject( cryptKey );
3292  if( useDatasize )
3293  cryptSetAttribute( cryptEnvelope, CRYPT_ENVINFO_DATASIZE,
3295  count = pushData( cryptEnvelope, ENVELOPE_TESTDATA,
3296  ENVELOPE_TESTDATA_SIZE, NULL, 0 );
3297  if( cryptStatusError( count ) )
3298  return( FALSE );
3299  count = popData( cryptEnvelope, globalBuffer, BUFFER_SIZE );
3300  if( cryptStatusError( count ) )
3301  return( FALSE );
3302  if( !destroyEnvelope( cryptEnvelope ) )
3303  return( FALSE );
3304 
3305  /* Tell them what happened */
3306  printf( "Enveloped data has size %d bytes.\n", count );
3307  debugDump( dumpFileName, globalBuffer, count );
3308 
3309  /* Make sure that the enveloped data is valid */
3310  status = cmsEnvelopeDecrypt( globalBuffer, count, externalKeyset,
3311  externalPassword, TRUE );
3312  if( status <= 0 ) /* Can be FALSE or an error code */
3313  return( FALSE );
3314 
3315  /* Clean up */
3316  puts( "Enveloping of CMS public-key encrypted data succeeded.\n" );
3317  return( TRUE );
3318  }
3319 
3320 static int cmsImportEnvelopedData( const char *fileName, const int fileNo )
3321  {
3322  CRYPT_ENVELOPE cryptEnvelope;
3323  BYTE *bufPtr = globalBuffer;
3324  char msgBuffer[ 128 ];
3325  int count, bytesIn, byteCount = 0, status;
3326 
3327  /* Read the test data */
3328  count = getFileSize( fileName ) + 10;
3329  if( count >= BUFFER_SIZE )
3330  {
3331  if( ( bufPtr = malloc( count ) ) == NULL )
3332  {
3333  printf( "Couldn't allocate test buffer of %d bytes, lin e%d.\n",
3334  count, __LINE__ );
3335  return( FALSE );
3336  }
3337  }
3338  sprintf( msgBuffer, "S/MIME EnvelopedData #%d", fileNo );
3339  count = readFileData( fileName, msgBuffer, bufPtr, count );
3340  if( count <= 0 )
3341  {
3342  if( bufPtr != globalBuffer )
3343  free( bufPtr );
3344  return( count );
3345  }
3346 
3347  /* Make sure that we can parse the data */
3348  if( !createDeenvelope( &cryptEnvelope ) )
3349  {
3350  if( bufPtr != globalBuffer )
3351  free( bufPtr );
3352  return( FALSE );
3353  }
3354  status = cryptPushData( cryptEnvelope, bufPtr, count, &bytesIn );
3355  while( status == CRYPT_ERROR_UNDERFLOW )
3356  {
3357  byteCount += bytesIn;
3358  status = cryptPushData( cryptEnvelope, bufPtr + byteCount,
3359  count - byteCount, &bytesIn );
3360  }
3361  if( !destroyEnvelope( cryptEnvelope ) )
3362  return( FALSE );
3363  if( bufPtr != globalBuffer )
3364  free( bufPtr );
3365  if( status == CRYPT_ENVELOPE_RESOURCE )
3366  {
3367  /* When we get to the CRYPT_ENVELOPE_RESOURCE stage we know that
3368  we've successfully processed all of the recipients, because
3369  cryptlib is asking us for a key to continue */
3370  status = CRYPT_OK;
3371  }
3372  if( cryptStatusError( status ) )
3373  {
3374  printf( "Couldn't de-envelope data, status = %d, line %d.\n",
3375  status, __LINE__ );
3376  return( FALSE );
3377  }
3378 
3379  puts( "S/MIME EnvelopedData import succeeded.\n" );
3380  return( TRUE );
3381  }
3382 
3383 int testCMSEnvelopePKCCrypt( void )
3384  {
3385  int value, status;
3386 
3387  if( !cmsEnvelopeCrypt( "smi_pkcn", FALSE, FALSE, FALSE, FALSE, CRYPT_UNUSED, CRYPT_UNUSED, NULL, NULL ) )
3388  return( FALSE ); /* Standard */
3389  if( !cmsEnvelopeCrypt( "smi_pkc", TRUE, FALSE, FALSE, FALSE, CRYPT_UNUSED, CRYPT_UNUSED, NULL, NULL ) )
3390  return( FALSE ); /* Datasize hint */
3391 
3392  /* Test enveloping with an IV-less stream cipher, which bypasses the usual
3393  CBC-mode block cipher handling. The alternative way of doing this is
3394  to manually add a CRYPT_CTXINFO_SESSIONKEY object, doing it this way is
3395  less work */
3398  status = cmsEnvelopeCrypt( "smi_pkcs", TRUE, TRUE, FALSE, FALSE, CRYPT_UNUSED, CRYPT_UNUSED, NULL, NULL );
3400  if( !status ) /* Datasize and stream cipher */
3401  return( status );
3402 
3403  /* Test enveloping with a cipher with a larger-than-usual block size */
3406  status = cmsEnvelopeCrypt( "smi_pkcb", TRUE, FALSE, TRUE, FALSE, CRYPT_UNUSED, CRYPT_UNUSED, NULL, NULL );
3408  return( status ); /* Datasize and large blocksize cipher */
3409  }
3410 
3411 int testCMSEnvelopePKCCryptEx( const CRYPT_HANDLE encryptContext,
3412  const CRYPT_HANDLE decryptKeyset,
3413  const C_STR password, const C_STR recipient )
3414  {
3415  int status;
3416 
3417  assert( ( encryptContext != CRYPT_UNUSED && recipient == NULL ) || \
3418  ( encryptContext == CRYPT_UNUSED && recipient != NULL ) );
3419 
3420  /* We can either provide the recipient's key directly as a pubkey
3421  context or indirectly as a recipient name. This is used to test
3422  a device's ability to act as a recipient key store */
3423  status = cmsEnvelopeCrypt( "smi_pkcd", TRUE, FALSE, FALSE, \
3424  ( recipient != NULL ) ? TRUE : FALSE, \
3425  encryptContext, decryptKeyset, password, \
3426  recipient );
3427  if( status == CRYPT_ERROR_NOTFOUND )
3428  { /* Datasize, keys in crypto device */
3429  puts( " (This is probably because the public key certificate was "
3430  "regenerated after\n the certificate stored with the "
3431  "private key was created, so that the\n private key can't "
3432  "be identified any more using the public key that was\n "
3433  "used for encryption. This can happen when the cryptlib "
3434  "self-test is run\n in separate stages, with one stage "
3435  "re-using data that was created\n earlier during a "
3436  "previous stage)." );
3437  return( FALSE );
3438  }
3439  return( status );
3440  }
3441 
3443  {
3444  CRYPT_KEYSET cryptKeyset;
3445  int status;
3446 
3447  /* The dual-certificate test uses cryptlib's internal key management to
3448  read the appropriate certificate from a database keyset, if this
3449  hasn't been set up then the test will fail so we try and detect the
3450  presence of the database keyset here. This isn't perfect since it
3451  requires that the database keyset be updated with the certificates in
3452  the same run as this test, but it's the best we can do */
3453  if( !doubleCertOK )
3454  {
3455  puts( "The certificate database wasn't updated with dual encryption/"
3456  "signing certs\nduring this test run (either because database "
3457  "keysets aren't enabled in this\nbuild of cryptlib or because "
3458  "only some portions of the self-tests are being\nrun), "
3459  "skipping the test of CMS enveloping with dual certs.\n" );
3460  return( TRUE );
3461  }
3462 
3463  /* Since we're using certs with the same DN and email address present
3464  in multiple certs, we can't use the generic user keyset but have to
3465  use one that has been set up to have multiple certs that differ
3466  only in keyUsage */
3467  status = cryptKeysetOpen( &cryptKeyset, CRYPT_UNUSED, CRYPT_KEYSET_FILE,
3469  if( cryptStatusError( status ) )
3470  {
3471  puts( "Couldn't find keyset with dual encryption/signature certs "
3472  "for test of dual certificate\nencryption." );
3473  return( FALSE );
3474  }
3475  status = cmsEnvelopeCrypt( "smi_pkcr", TRUE, FALSE, FALSE, FALSE,
3476  CRYPT_UNUSED, cryptKeyset,
3478  TEXT( "[email protected]" ) );
3479  cryptKeysetClose( cryptKeyset );
3480  if( status == CRYPT_ERROR_NOTFOUND )
3481  { /* Datasize, recipient */
3482  puts( " (This is probably because the public key certificate was "
3483  "regenerated after\n the certificate stored with the "
3484  "private key was created, so that the\n private key can't "
3485  "be identified any more using the public key that was\n "
3486  "used for encryption. This can happen when the cryptlib "
3487  "self-test is run\n in separate stages, with one stage "
3488  "re-using data that was created\n earlier during a "
3489  "previous stage)." );
3490  return( FALSE );
3491  }
3492  return( status );
3493  }
3494 
3495 /****************************************************************************
3496 * *
3497 * Test Data Import Routines *
3498 * *
3499 ****************************************************************************/
3500 
3501 /* Import S/MIME signed data */
3502 
3504  {
3505  FILE *filePtr;
3506  BYTE fileName[ BUFFER_SIZE ];
3507  int i;
3508 
3509  /* Make sure that the test data is present so that we can return a
3510  useful error message */
3512  if( ( filePtr = fopen( fileName, "rb" ) ) == NULL )
3513  {
3514  puts( "Couldn't find S/MIME SignedData file, skipping test of "
3515  "SignedData import..." );
3516  return( TRUE );
3517  }
3518  fclose( filePtr );
3519 
3520  /* There are many encoding variations possible for signed data so we try
3521  a representative sample to make sure that the code works in all
3522  cases */
3523  for( i = 1; i <= 3; i++ )
3524  {
3526  if( !cmsImportSignedData( fileName, i ) && i != 2 )
3527  {
3528  /* AuthentiCode sig check fails for some reason */
3529  return( FALSE );
3530  }
3531  }
3532 
3533  puts( "Import of S/MIME SignedData succeeded.\n" );
3534 
3535  return( TRUE );
3536  }
3537 
3538 /* Import S/MIME encrypted data */
3539 
3541  {
3542  FILE *filePtr;
3543  BYTE fileName[ BUFFER_SIZE ];
3544  int i;
3545 
3546  /* Make sure that the test data is present so that we can return a
3547  useful error message */
3549  if( ( filePtr = fopen( fileName, "rb" ) ) == NULL )
3550  {
3551  puts( "Couldn't find S/MIME EnvelopedData file, skipping test of "
3552  "EnvelopedData import..." );
3553  return( TRUE );
3554  }
3555  fclose( filePtr );
3556 
3557  /* Enveloped data requires decryption keys that aren't generally
3558  available, so all that we do in this case is make sure that we can
3559  parse the data */
3560  for( i = 1; i <= 1; i++ )
3561  {
3563  if( !cmsImportEnvelopedData( fileName, i ) )
3564  return( FALSE );
3565  }
3566 
3567  puts( "Import of S/MIME EnvelopedData succeeded.\n" );
3568 
3569  return( TRUE );
3570  }
3571 
3572 /* Import CMS password-encrypted/authenticated data */
3573 
3575  {
3576  FILE *filePtr;
3577  BYTE fileName[ BUFFER_SIZE ];
3578  int i;
3579 
3580  /* Make sure that the test data is present so that we can return a
3581  useful error message */
3583  if( ( filePtr = fopen( fileName, "rb" ) ) == NULL )
3584  {
3585  puts( "Couldn't find CMS EnvelopedData file, skipping test of "
3586  "EnvelopedData/AuthentcatedData import..." );
3587  return( TRUE );
3588  }
3589  fclose( filePtr );
3590 
3591  /* Process the password-protected data. The files are:
3592 
3593  File 1: CMS Authenticated data, AES-256 key wrap with HMAC-SHA1.
3594 
3595  File 2: CMS Enveloped data, AES-128 key wrap with AES-128 */
3596  for( i = 1; i <= 2; i++ )
3597  {
3598  int count;
3599 
3601  count = readFileData( fileName, "CMS password-encrypted/authd data",
3602  globalBuffer, BUFFER_SIZE );
3603  if( count <= 0 )
3604  return( FALSE );
3605  if( !cmsEnvelopeDecrypt( globalBuffer, count, CRYPT_UNUSED,
3606  TEST_PASSWORD, FALSE ) )
3607  return( FALSE );
3608  }
3609 
3610  puts( "Import of CMS password-encrypted/authenticated data "
3611  "succeeded.\n" );
3612 
3613  return( TRUE );
3614  }
3615 
3616 /* Import PGP 2.x and OpenPGP-generated password-encrypted data */
3617 
3619  {
3620  BYTE fileName[ BUFFER_SIZE ];
3621  int count;
3622 
3623  /* Process the PGP 2.x data: IDEA with MD5 hash. Create with:
3624 
3625  pgp -c +compress=off -o conv_enc1.pgp test.txt */
3627  count = readFileData( fileName, "PGP password-encrypted data",
3628  globalBuffer, BUFFER_SIZE );
3629  if( count <= 0 )
3630  return( FALSE );
3631  count = envelopePasswordDecrypt( globalBuffer, count );
3632  if( count <= 0 )
3633  return( FALSE );
3634  if( count != ENVELOPE_TESTDATA_SIZE || \
3635  memcmp( globalBuffer, ENVELOPE_PGP_TESTDATA,
3637  {
3638  puts( "De-enveloped data != original data." );
3639  return( FALSE );
3640  }
3641  puts( "Import of PGP password-encrypted data succeeded." );
3642 
3643  /* Process the OpenPGP data. The files are:
3644 
3645  File 2: 3DES with SHA1 hash. Create with:
3646 
3647  pgp65 -c +compress=off -o conv_enc2.pgp test.txt
3648 
3649  File 1: 3DES with SHA1 non-iterated hash. Create with:
3650 
3651  gpg -c -z 0 --cipher-algo 3des --s2k-mode 1 -o conv_enc3.pgp test.txt */
3653  count = readFileData( fileName, "OpenPGP password-encrypted data",
3654  globalBuffer, BUFFER_SIZE );
3655  if( count <= 0 )
3656  return( FALSE );
3657  if( !envelopePasswordDecrypt( globalBuffer, count ) )
3658  return( FALSE );
3659  if( memcmp( globalBuffer, ENVELOPE_PGP_TESTDATA,
3661  {
3662  puts( "De-enveloped data != original data." );
3663  return( FALSE );
3664  }
3666  count = readFileData( fileName, "OpenPGP password-encrypted data",
3667  globalBuffer, BUFFER_SIZE );
3668  if( count <= 0 )
3669  return( FALSE );
3670  if( !envelopePasswordDecrypt( globalBuffer, count ) )
3671  return( FALSE );
3672  if( memcmp( globalBuffer, ENVELOPE_PGP_TESTDATA,
3674  {
3675  puts( "De-enveloped data != original data." );
3676  return( FALSE );
3677  }
3678  puts( "Import of OpenPGP password-encrypted data succeeded.\n" );
3679 
3680  return( TRUE );
3681  }
3682 
3683 /* Import PGP 2.x and OpenPGP-generated PKC-encrypted data */
3684 
3686  {
3687  BYTE fileName[ BUFFER_SIZE ];
3688  int count;
3689 
3690  /* Process the PGP 2.x encrypted data */
3692  count = readFileData( fileName, "PGP-encrypted data", globalBuffer,
3693  BUFFER_SIZE );
3694  if( count <= 0 )
3695  return( FALSE );
3696  count = envelopePKCDecrypt( globalBuffer, count, KEYFILE_PGP,
3697  CRYPT_UNUSED );
3698  if( count <= 0 )
3699  return( FALSE );
3700  if( count != ENVELOPE_TESTDATA_SIZE || \
3701  memcmp( globalBuffer, ENVELOPE_PGP_TESTDATA,
3703  {
3704  puts( "De-enveloped data != original data." );
3705  return( FALSE );
3706  }
3708  count = readFileData( fileName, "PGP (NAI)-encrypted data", globalBuffer,
3709  BUFFER_SIZE );
3710  if( count <= 0 )
3711  return( FALSE );
3712  count = envelopePKCDecrypt( globalBuffer, count, KEYFILE_NAIPGP,
3713  CRYPT_UNUSED );
3714  if( count <= 0 )
3715  return( FALSE );
3716  if( globalBuffer[ 0 ] != 0xA3 || globalBuffer[ 1 ] != 0x01 || \
3717  globalBuffer[ 2 ] != 0x5B || globalBuffer[ 3 ] != 0x53 )
3718  {
3719  puts( "De-enveloped data != original data." );
3720  return( FALSE );
3721  }
3722  puts( "Import of PGP-encrypted data succeeded." );
3723 
3724  /* Process the OpenPGP encrypted data. The files are:
3725 
3726  File 1: RSA with 3DES. Create with:
3727 
3728  pgpo -e +pubring=".\pubring.pgp" +compress=off -o gpg_enc1.pgp -r test test.txt
3729 
3730  (In theory it could be created with
3731  gpg -e -z 0 --homedir . --always-trust -r test test.txt
3732  and pubring.pgp renamed to pubring.gpg, however GPG won't allow
3733  the use of the RSA key in pubring.pgp no matter what command-
3734  line options you specify because it's not self-signed).
3735 
3736  File 2: Elgamal and AES with MDC. Create with:
3737 
3738  cp sec_hash.gpg secring.gpg
3739  cp pub_hash.gpg pubring.gpg
3740  gpg -e -z 0 --homedir . -o gpg_enc2.gpg -r test1 test.txt
3741  rm secring.gpg pubring.gpg
3742 
3743  File 3: Elgamal and Blowfish with MDC. Create with:
3744 
3745  cp sec_hash.gpg secring.gpg
3746  cp pub_hash.gpg pubring.gpg
3747  gpg -e -z 0 --homedir . --cipher-algo blowfish -o gpg_enc3.gpg -r test1 test.txt
3748  rm secring.gpg pubring.gpg
3749 
3750  File 4: Elgamal and AES with MDC and partial lengths (not sure how
3751  this was created) */
3753  count = readFileData( fileName, "OpenPGP (GPG)-encrypted data",
3754  globalBuffer, BUFFER_SIZE );
3755  if( count <= 0 )
3756  return( FALSE );
3757  count = envelopePKCDecrypt( globalBuffer, count, KEYFILE_PGP,
3758  CRYPT_UNUSED );
3759  if( count <= 0 )
3760  return( FALSE );
3761  if( count != ENVELOPE_TESTDATA_SIZE || \
3762  memcmp( globalBuffer, ENVELOPE_PGP_TESTDATA,
3764  {
3765  puts( "De-enveloped data != original data." );
3766  return( FALSE );
3767  }
3769  count = readFileData( fileName, "OpenPGP (GPG)-encrypted data with "
3770  "AES + MDC", globalBuffer, BUFFER_SIZE );
3771  if( count <= 0 )
3772  return( FALSE );
3773  count = envelopePKCDecrypt( globalBuffer, count, KEYFILE_OPENPGP_HASH,
3774  CRYPT_UNUSED );
3775  if( count <= 0 )
3776  return( FALSE );
3777  if( count != ENVELOPE_TESTDATA_SIZE || \
3778  memcmp( globalBuffer, ENVELOPE_PGP_TESTDATA,
3780  {
3781  puts( "De-enveloped data != original data." );
3782  return( FALSE );
3783  }
3785  count = readFileData( fileName, "OpenPGP (GPG)-encrypted data with "
3786  "Blowfish + MDC", globalBuffer, BUFFER_SIZE );
3787  if( count <= 0 )
3788  return( FALSE );
3789  count = envelopePKCDecrypt( globalBuffer, count, KEYFILE_OPENPGP_HASH,
3790  CRYPT_UNUSED );
3791  if( count <= 0 )
3792  return( FALSE );
3793  if( count != ENVELOPE_TESTDATA_SIZE || \
3794  memcmp( globalBuffer, ENVELOPE_PGP_TESTDATA,
3796  {
3797  puts( "De-enveloped data != original data." );
3798  return( FALSE );
3799  }
3800 #if 0 /* Uses partial lengths */
3802  count = readFileData( fileName, "OpenPGP (GPG)-encrypted data with "
3803  "partial lengths", globalBuffer, BUFFER_SIZE );
3804  if( count <= 0 )
3805  return( FALSE );
3806  count = envelopePKCDecrypt( globalBuffer, count, KEYFILE_OPENPGP_PARTIAL,
3807  CRYPT_UNUSED );
3808  if( count <= 0 )
3809  return( FALSE );
3810  count = envelopeDecompress( globalBuffer, BUFFER_SIZE, count );
3811  if( count <= 0 )
3812  return( FALSE );
3813  if( count < 600 || memcmp( globalBuffer, "\n\n<sect>Vorwort\n", 16 ) )
3814  {
3815  puts( "De-enveloped data != original data." );
3816  return( FALSE );
3817  }
3818 #endif /* 0 */
3819  puts( "Import of OpenPGP-encrypted data succeeded.\n" );
3820 
3821  return( TRUE );
3822  }
3823 
3824 /* Import PGP 2.x and OpenPGP-generated signed data */
3825 
3827  {
3829  BYTE fileName[ BUFFER_SIZE ];
3830  int count, status;
3831 
3832  /* Process the PGP 2.x signed data. Create with:
3833 
3834  pgp -s +secring="secring.pgp" +pubring="pubring.pgp" -u test test.txt */
3836  count = readFileData( fileName, "PGP-signed data", globalBuffer,
3837  BUFFER_SIZE );
3838  if( count <= 0 )
3839  return( FALSE );
3840  count = envelopeSigCheck( globalBuffer, count, CRYPT_UNUSED,
3842  CRYPT_FORMAT_PGP );
3843  if( count <= 0 )
3844  return( FALSE );
3845  if( count != ENVELOPE_TESTDATA_SIZE || \
3846  memcmp( globalBuffer, ENVELOPE_PGP_TESTDATA,
3848  {
3849  puts( "De-enveloped data != original data." );
3850  return( FALSE );
3851  }
3852  puts( "Import of PGP-signed data succeeded." );
3853 
3854 #if 0 /* Disabled because it uses a 512-bit sig and there doesn't appear to
3855  be any way to create a new file in this format */
3856  /* Process the OpenPGP (actually a weird 2.x/OpenPGP hybrid produced by
3857  PGP 5.0) signed data. In theory this could be created with:
3858 
3859  pgpo -s +secring="secring.pgp" +pubring="pubring.pgp" +compress=off -o signed2.pgp -u test test.txt
3860 
3861  but the exact details of how to create this packet are a mystery, it
3862  starts with a marker packet and then a one-pass sig, which isn't
3863  generated by default by any of the PGP 5.x or 6.x versions */
3865  count = readFileData( fileName, "PGP 2.x/OpenPGP-hybrid-signed data",
3866  globalBuffer, BUFFER_SIZE );
3867  if( count <= 0 )
3868  return( FALSE );
3869  count = envelopeSigCheck( globalBuffer, count, CRYPT_UNUSED,
3871  CRYPT_FORMAT_PGP );
3872  if( count <= 0 )
3873  return( FALSE );
3874  if( count != ENVELOPE_TESTDATA_SIZE || \
3875  memcmp( globalBuffer, ENVELOPE_PGP_TESTDATA,
3877  {
3878  puts( "De-enveloped data != original data." );
3879  return( FALSE );
3880  }
3881  puts( "Import of PGP 2.x/OpenPGP-hybrid-signed data succeeded." );
3882 #endif /* 0 */
3883 
3884  /* Process the OpenPGP signed data: DSA with SHA1. Create with:
3885 
3886  cp sec_hash.gpg secring.gpg
3887  cp pub_hash.gpg pubring.gpg
3888  gpg -s -z 0 --homedir . -o signed3.pgp test.txt
3889  rm secring.gpg pubring.gpg */
3891  count = readFileData( fileName, "OpenPGP-signed data",
3892  globalBuffer, BUFFER_SIZE );
3893  if( count <= 0 )
3894  return( FALSE );
3895  count = envelopeSigCheck( globalBuffer, count, CRYPT_UNUSED,
3897  CRYPT_FORMAT_PGP );
3898  if( count <= 0 )
3899  return( FALSE );
3900  if( count != ENVELOPE_TESTDATA_SIZE || \
3901  memcmp( globalBuffer, ENVELOPE_PGP_TESTDATA,
3903  {
3904  puts( "De-enveloped data != original data." );
3905  return( FALSE );
3906  }
3907  puts( "Import of OpenPGP-signed data succeeded." );
3908 
3909  /* Process the OpenPGP detached signed data. Create with:
3910 
3911  cp sec_hash.gpg secring.gpg
3912  cp pub_hash.gpg pubring.gpg
3913  gpg -b -z 0 --openpgp --homedir . -o signed4.pgp test.txt
3914  rm secring.gpg pubring.gpg
3915 
3916  (the --openpgp is for another GPG bug, without it it'll generate
3917  v3 sigs as if --force-v3-sigs had been specified). The data is
3918  provided externally so we have to hash it ourselves. Since PGP
3919  hashes further data after hashing the content, we can't complete
3920  the hashing but have to use the partially-completed hash */
3921  status = cryptCreateContext( &hashContext, CRYPT_UNUSED, CRYPT_ALGO_SHA );
3922  if( cryptStatusOK( status ) )
3923  status = cryptEncrypt( hashContext, ENVELOPE_PGP_TESTDATA,
3925  if( cryptStatusError( status ) )
3926  {
3927  puts( "Couldn't create external hash of data." );
3928  return( FALSE );
3929  }
3931  count = readFileData( fileName, "OpenPGP-signed data with "
3932  "externally-supplied hash", globalBuffer,
3933  BUFFER_SIZE );
3934  if( count <= 0 )
3935  return( FALSE );
3936  count = envelopeSigCheck( globalBuffer, count, hashContext,
3938  CRYPT_FORMAT_PGP );
3939  cryptDestroyContext( hashContext );
3940  if( count <= 0 )
3941  return( FALSE );
3942  puts( "Import of OpenPGP-signed data with externally-supplied hash "
3943  "succeeded.\n" );
3944 
3945  return( TRUE );
3946  }
3947 
3948 /* Import PGP 2.x and OpenPGP-generated compressed data */
3949 
3951  {
3952  BYTE fileName[ BUFFER_SIZE ], *bufPtr;
3953  int count;
3954 
3955  /* Since this needs a nontrivial amount of data for the compression, we
3956  use a dynamically-allocated buffer */
3957  if( ( bufPtr = malloc( FILEBUFFER_SIZE ) ) == NULL )
3958  {
3959  puts( "Couldn't allocate test buffer." );
3960  return( FALSE );
3961  }
3962 
3963  /* Process the PGP 2.x compressed data */
3965  count = readFileData( fileName, "PGP 2.x compressed data",
3966  bufPtr, FILEBUFFER_SIZE );
3967  if( count <= 0 )
3968  {
3969  free( bufPtr );
3970  return( FALSE );
3971  }
3972  count = envelopeDecompress( bufPtr, FILEBUFFER_SIZE, count );
3973  if( count && memcmp( bufPtr, ENVELOPE_COMPRESSEDDATA,
3975  {
3976  puts( "De-enveloped data != original data." );
3977  free( bufPtr );
3978  return( FALSE );
3979  }
3980  if( count <= 0 )
3981  {
3982  free( bufPtr );
3983  return( FALSE );
3984  }
3985  puts( "Import of PGP 2.x compressed data succeeded.\n" );
3986 
3987  /* Process the OpenPGP compressed nested data. Create with:
3988 
3989  cp sec_hash.gpg secring.gpg
3990  cp pub_hash.gpg pubring.gpg
3991  gpg -s --openpgp --homedir . -o copr2.pgp test.c
3992  rm secring.gpg pubring.gpg
3993 
3994  with the same note as before for GPG bugs and --openpgp */
3996  count = readFileData( fileName, "OpenPGP compressed signed data",
3997  bufPtr, FILEBUFFER_SIZE );
3998  if( count <= 0 )
3999  {
4000  free( bufPtr );
4001  return( FALSE );
4002  }
4003  count = envelopeDecompress( bufPtr, FILEBUFFER_SIZE, count );
4004  if( count && \
4005  ( bufPtr[ 0 ] != 0x90 || bufPtr[ 1 ] != 0x0D || \
4006  bufPtr[ 2 ] != 0x03 || bufPtr[ 3 ] != 0x00 ) )
4007  {
4008  puts( "De-enveloped data != original data." );
4009  free( bufPtr );
4010  return( FALSE );
4011  }
4012  if( count <= 0 )
4013  {
4014  free( bufPtr );
4015  return( FALSE );
4016  }
4017  memcpy( globalBuffer, bufPtr, count );
4018  free( bufPtr );
4019  count = envelopeSigCheck( globalBuffer, count, CRYPT_UNUSED,
4021  CRYPT_FORMAT_PGP );
4022  if( count <= 0 )
4023  return( FALSE );
4024  if( count && memcmp( globalBuffer, ENVELOPE_COMPRESSEDDATA,
4026  {
4027  puts( "De-enveloped data != original data." );
4028  return( FALSE );
4029  }
4030  puts( "Import of OpenPGP compressed signed data succeeded.\n" );
4031 
4032  return( TRUE );
4033  }
4034 
4035 /* Generic test routines used for debugging. These are only meant to be
4036  used interactively, and throw exceptions rather than returning status
4037  values */
4038 
4039 static void dataImport( void *buffer, const int length,
4040  const BOOLEAN resultBad )
4041  {
4042  CRYPT_ENVELOPE cryptEnvelope;
4043  int count;
4044 
4045  createDeenvelope( &cryptEnvelope );
4046  count = pushData( cryptEnvelope, buffer, length, NULL, 0 );
4047  if( resultBad )
4048  {
4049  assert( cryptStatusError( count ) );
4050  return;
4051  }
4052  assert( !cryptStatusError( count ) );
4053  count = popData( cryptEnvelope, buffer, length );
4054  assert( !cryptStatusError( count ) );
4055  destroyEnvelope( cryptEnvelope );
4056  }
4057 
4058 void xxxDataImport( const char *fileName )
4059  {
4060  BYTE *bufPtr = globalBuffer;
4061  int count;
4062 
4063  count = getFileSize( fileName ) + 10;
4064  if( count >= BUFFER_SIZE && \
4065  ( bufPtr = malloc( count ) ) == NULL )
4066  {
4067  assert( 0 );
4068  return;
4069  }
4070  count = readFileData( fileName, "Generic test data", bufPtr, count );
4071  assert( count > 0 );
4072  dataImport( bufPtr, count, FALSE );
4073  if( bufPtr != globalBuffer )
4074  free( bufPtr );
4075  }
4076 
4077 void xxxSignedDataImport( const char *fileName )
4078  {
4079  BYTE *bufPtr = globalBuffer;
4080  int count, status;
4081 
4082  count = getFileSize( fileName ) + 10;
4083  if( count >= BUFFER_SIZE && \
4084  ( bufPtr = malloc( count ) ) == NULL )
4085  {
4086  assert( 0 );
4087  return;
4088  }
4089  count = readFileData( fileName, "S/MIME test data", bufPtr, count );
4090  assert( count > 0 );
4091  status = cmsEnvelopeSigCheck( bufPtr, count, CRYPT_UNUSED, CRYPT_UNUSED,
4092  FALSE, FALSE, FALSE, FALSE, FALSE );
4093  assert( status > 0 );
4094  if( bufPtr != globalBuffer )
4095  free( bufPtr );
4096  }
4097 
4098 void xxxEncryptedDataImport( const char *fileName )
4099  {
4100  int count, status;
4101 
4102  count = getFileSize( fileName ) + 10;
4103  if( count >= BUFFER_SIZE )
4104  assert( 0 );
4105  count = readFileData( fileName, "S/MIME test data", globalBuffer,
4106  count );
4107  assert( count > 0 );
4108  status = cmsEnvelopeDecrypt( globalBuffer, count, CRYPT_UNUSED, NULL,
4109  FALSE );
4110  assert( status > 0 );
4111  }
4112 
4113 void xxxEnvelopeTest( void )
4114  {
4115  CRYPT_CERTIFICATE cryptCert;
4116 
4117  importCertFile( &cryptCert, "r:/cert.der" );
4118 
4119  envelopePKCCrypt( "r:/test.p7m", TRUE, KEYFILE_NONE, FALSE,
4120  FALSE, FALSE, TRUE, CRYPT_FORMAT_CMS, cryptCert, 0 );
4121  }
4122 #endif /* TEST_ENVELOPE || TEST_SESSION */