cryptlib  3.4.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros
stress.c
Go to the documentation of this file.
1 /****************************************************************************
2 * *
3 * cryptlib Test Code *
4 * Copyright Peter Gutmann 1995-2004 *
5 * *
6 ****************************************************************************/
7 
8 #include "cryptlib.h"
9 #include "test/test.h"
10 
11 #if defined( __MVS__ ) || defined( __VMCMS__ )
12  /* Suspend conversion of literals to ASCII. */
13  #pragma convlit( suspend )
14 #endif /* EBCDIC systems */
15 
16 /* Define the following to perform a smoke test on the cryptlib kernel.
17  This includes:
18 
19  Stress test: Create 10K objects and read/write some attributes
20  Data processing test: Encrypt/hash/MAC a buffer in a variable number
21  of variable-size blocks, then decrypt/hash/MAC with different
22  blocks and make sure the results match.
23  Kernel check test: Run through every possible object type and attribute
24  making sure we don't trigger any assertions.
25  Simple threading stress test: DES-encrypt 100 data blocks in threads.
26  Complex threading stress test: Encrypted and signed enveloping.
27  Threading continuous test: Envelope data in threads until interrupted.
28 
29  Note that these are exhaustive tests that check large numbers of objects
30  or parameter types and combinations so they can take some time to run to
31  completion */
32 
33 /* #define SMOKE_TEST */
34 
35 /****************************************************************************
36 * *
37 * Stress Test *
38 * *
39 ****************************************************************************/
40 
41 #ifdef SMOKE_TEST
42 
43 #define NO_OBJECTS 10000 /* Can't exceed MAX_OBJECTS in cryptkrn.h */
44 
45 static void testStressObjects( void )
46  {
47  CRYPT_HANDLE *handleArray = malloc( NO_OBJECTS * sizeof( CRYPT_HANDLE ) );
48  BYTE hash[ CRYPT_MAX_HASHSIZE ];
49  int i, length, status;
50 
51  printf( "Running object stress test." );
52  assert( handleArray != NULL );
53  for( i = 0; i < NO_OBJECTS; i++ )
54  {
55  status = cryptCreateContext( &handleArray[ i ], CRYPT_UNUSED,
57  if( cryptStatusError( status ) )
58  printf( "cryptEncrypt() failed at %d with status %d.\n", i,
59  status );
60  }
61  printf( "." );
62  for( i = 0; i < NO_OBJECTS; i++ )
63  {
64  status = cryptEncrypt( handleArray[ i ], "12345678", 8 );
65  if( cryptStatusError( status ) )
66  printf( "cryptEncrypt() failed at %d with status %d.\n", i, status );
67  }
68  printf( "." );
69  for( i = 0; i < NO_OBJECTS; i++ )
70  {
71  status = cryptEncrypt( handleArray[ i ], "", 0 );
72  if( cryptStatusError( status ) )
73  printf( "cryptEncrypt() failed at %d with status %d.\n", i,
74  status );
75  }
76  printf( "." );
77  for( i = 0; i < NO_OBJECTS; i++ )
78  {
79  status = cryptGetAttributeString( handleArray[ i ],
80  CRYPT_CTXINFO_HASHVALUE, hash, &length );
81  if( cryptStatusError( status ) )
82  printf( "cryptEncrypt() failed at %d with status %d.\n", i,
83  status );
84  }
85  printf( "." );
86  for( i = 0; i < NO_OBJECTS; i++ )
87  {
88  status = cryptDestroyContext( handleArray[ i ] );
89  if( cryptStatusError( status ) )
90  printf( "cryptEncrypt() failed at %d with status %d.\n", i,
91  status );
92  }
93  free( handleArray );
94  puts( "." );
95  }
96 
97 /****************************************************************************
98 * *
99 * Data Processing Test *
100 * *
101 ****************************************************************************/
102 
103 /* Data processing test */
104 
105 #define DATABUFFER_SIZE 2048
106 #define MAX_BLOCKS 16
107 
108 #define roundUp( size, roundSize ) \
109  ( ( ( size ) + ( ( roundSize ) - 1 ) ) & ~( ( roundSize ) - 1 ) )
110 
111 #ifdef __WINDOWS__
112  typedef int ( __stdcall *CRYPT_FUNCTION )( const CRYPT_CONTEXT cryptContext,
113  void *data, const int length );
114 #else
115  typedef int ( *CRYPT_FUNCTION )( const CRYPT_CONTEXT cryptContext,
116  void *data, const int length );
117 #endif /* __WINDOWS__ */
118 
119 static int processData( const CRYPT_CONTEXT cryptContext, BYTE *buffer,
120  const int noBlocks, const int blockSize,
121  CRYPT_FUNCTION cryptFunction )
122  {
123  int offset = 0, i, status;
124 
125  /* Encrypt the data in variable-length blocks. The technique for
126  selecting lengths isn't perfect since it tends to put large blocks
127  at the start and small ones at the end, but it's good enough for
128  general testing */
129  for( i = 0; i < noBlocks - 1; i++ )
130  {
131  int noBytes = rand() % ( DATABUFFER_SIZE - offset - \
132  ( blockSize * ( noBlocks - i ) ) );
133  if( !noBytes )
134  noBytes = 1;
135  if( blockSize > 1 )
136  noBytes = roundUp( noBytes, blockSize );
137  status = cryptFunction( cryptContext, buffer + offset, noBytes );
138  if( cryptStatusError( status ) )
139  return( status );
140  offset += noBytes;
141  }
142  status = cryptFunction( cryptContext, buffer + offset,
143  DATABUFFER_SIZE - offset );
144  if( cryptStatusOK( status ) )
145  status = cryptFunction( cryptContext, "", 0 );
146  return( status );
147  }
148 
149 static int testProcessing( const CRYPT_ALGO_TYPE cryptAlgo,
151  const CRYPT_QUERY_INFO cryptQueryInfo )
152  {
153  BYTE buffer1[ DATABUFFER_SIZE ], buffer2[ DATABUFFER_SIZE ];
154  BYTE hash1[ CRYPT_MAX_HASHSIZE ], hash2[ CRYPT_MAX_HASHSIZE ];
155  const int blockSize = ( cryptMode == CRYPT_MODE_ECB || \
156  cryptMode == CRYPT_MODE_CBC ) ? \
157  cryptQueryInfo.blockSize : 1;
158  int length1, length2, i;
159 
160  /* Initialise the buffers with a known data pattern */
161  memset( buffer1, '*', DATABUFFER_SIZE );
162  memcpy( buffer1, "12345678", 8 );
163  memcpy( buffer2, buffer1, DATABUFFER_SIZE );
164 
165  /* Process the data using various block sizes */
166  printf( "Testing algorithm %d, mode %d, for %d-byte buffer with\n block "
167  "count ", cryptAlgo, ( cryptMode == CRYPT_UNUSED ) ? 0 : cryptMode,
168  DATABUFFER_SIZE );
169  for( i = 1; i <= MAX_BLOCKS; i++ )
170  {
172  int status;
173 
174  memcpy( buffer1, buffer2, DATABUFFER_SIZE );
175  printf( "%d%s ", i, ( i == MAX_BLOCKS ) ? "." : "," );
176 
177  /* Encrypt the data with random block sizes */
178  status = cryptCreateContext( &cryptContext, CRYPT_UNUSED, cryptAlgo );
179  if( cryptStatusError( status ) )
180  return( status );
181  if( cryptMode != CRYPT_UNUSED )
182  {
183  status = cryptSetAttribute( cryptContext, CRYPT_CTXINFO_MODE,
184  cryptMode );
185  if( cryptStatusError( status ) )
186  return( status );
187  if( cryptMode != CRYPT_MODE_ECB && cryptAlgo != CRYPT_ALGO_RC4 )
188  {
189  status = cryptSetAttributeString( cryptContext, CRYPT_CTXINFO_IV,
190  "1234567887654321", cryptQueryInfo.blockSize );
191  if( cryptStatusError( status ) )
192  return( status );
193  }
194  }
195  if( cryptQueryInfo.keySize )
196  {
197  status = cryptSetAttributeString( cryptContext, CRYPT_CTXINFO_KEY,
198  "12345678876543211234567887654321",
199  cryptQueryInfo.keySize );
200  if( cryptStatusError( status ) )
201  return( status );
202  }
203  status = processData( cryptContext, buffer1, i, blockSize,
204  cryptEncrypt );
205  if( cryptStatusError( status ) )
206  return( status );
207  if( cryptAlgo >= CRYPT_ALGO_FIRST_HASH )
208  {
209  status = cryptGetAttributeString( cryptContext,
210  CRYPT_CTXINFO_HASHVALUE, hash1, &length1 );
211  if( cryptStatusError( status ) )
212  return( status );
213  }
214  status = cryptDestroyContext( cryptContext );
215  if( cryptStatusError( status ) )
216  return( status );
217 
218  /* Decrypt the data again with random block sizes */
219  status = cryptCreateContext( &cryptContext, CRYPT_UNUSED, cryptAlgo );
220  if( cryptStatusError( status ) )
221  return( status );
222  if( cryptMode != CRYPT_UNUSED )
223  {
224  status = cryptSetAttribute( cryptContext, CRYPT_CTXINFO_MODE,
225  cryptMode );
226  if( cryptStatusError( status ) )
227  return( status );
228  if( cryptMode != CRYPT_MODE_ECB && cryptAlgo != CRYPT_ALGO_RC4 )
229  {
230  status = cryptSetAttributeString( cryptContext, CRYPT_CTXINFO_IV,
231  "1234567887654321", cryptQueryInfo.blockSize );
232  if( cryptStatusError( status ) )
233  return( status );
234  }
235  }
236  if( cryptQueryInfo.keySize )
237  {
238  status = cryptSetAttributeString( cryptContext, CRYPT_CTXINFO_KEY,
239  "12345678876543211234567887654321",
240  cryptQueryInfo.keySize );
241  if( cryptStatusError( status ) )
242  return( status );
243  }
244  status = processData( cryptContext, buffer1, i, blockSize,
245  cryptDecrypt );
246  if( cryptStatusError( status ) )
247  return( status );
248  if( cryptAlgo >= CRYPT_ALGO_FIRST_HASH )
249  {
250  status = cryptGetAttributeString( cryptContext,
251  CRYPT_CTXINFO_HASHVALUE, hash2, &length2 );
252  if( cryptStatusError( status ) )
253  return( status );
254  }
255  status = cryptDestroyContext( cryptContext );
256  if( cryptStatusError( status ) )
257  return( status );
258 
259  /* Make sure the values match */
260  if( cryptAlgo >= CRYPT_ALGO_FIRST_HASH )
261  {
262  if( ( length1 != length2 ) || memcmp( hash1, hash2, length1 ) )
263  {
264  puts( "Error: Hash value of identical buffers differs." );
265  return( -1234 );
266  }
267  }
268  else
269  if( memcmp( buffer1, buffer2, DATABUFFER_SIZE ) )
270  {
271  printf( "Decrypted data != encrypted data for algorithm %d.\n",
272  cryptAlgo );
273  return( -1234 );
274  }
275  }
276  printf( "\n" );
277 
278  return( CRYPT_OK );
279  }
280 
281 static void testDataProcessing( void )
282  {
283  CRYPT_QUERY_INFO cryptQueryInfo;
285  int errorCount = 0, status;
286 
287  for( cryptAlgo = CRYPT_ALGO_FIRST_CONVENTIONAL;
288  cryptAlgo <= CRYPT_ALGO_LAST_CONVENTIONAL; cryptAlgo++ )
289  {
290  if( cryptStatusOK( cryptQueryCapability( cryptAlgo,
291  &cryptQueryInfo ) ) )
292  {
293  if( cryptAlgo != CRYPT_ALGO_RC4 )
294  {
295  status = testProcessing( cryptAlgo, CRYPT_MODE_ECB,
296  cryptQueryInfo );
297  if( cryptStatusError( status ) )
298  {
299  printf( "\nAlgorithm %d ECB mode processing failed with "
300  "status %d.\n", cryptAlgo, status );
301  errorCount++;
302  }
303  status = testProcessing( cryptAlgo, CRYPT_MODE_CBC,
304  cryptQueryInfo );
305  if( cryptStatusError( status ) )
306  {
307  printf( "\nAlgorithm %d CBC mode processing failed with "
308  "status %d.\n", cryptAlgo, status );
309  errorCount++;
310  }
311  status = testProcessing( cryptAlgo, CRYPT_MODE_CFB,
312  cryptQueryInfo );
313  if( cryptStatusError( status ) )
314  {
315  printf( "\nAlgorithm %d CFB mode processing failed with "
316  "status %d.\n", cryptAlgo, status );
317  errorCount++;
318  }
319  status = testProcessing( cryptAlgo, CRYPT_MODE_GCM,
320  cryptQueryInfo );
321  if( cryptStatusError( status ) )
322  {
323  printf( "\nAlgorithm %d GCM mode processing failed with "
324  "status %d.\n", cryptAlgo, status );
325  errorCount++;
326  }
327  }
328  status = testProcessing( cryptAlgo, CRYPT_MODE_OFB,
329  cryptQueryInfo );
330  if( cryptStatusError( status ) )
331  {
332  printf( "\nAlgorithm %d OFB mode processing failed with "
333  "status %d.\n", cryptAlgo, status );
334  errorCount++;
335  }
336  }
337  }
338  for( cryptAlgo = CRYPT_ALGO_FIRST_HASH;
339  cryptAlgo <= CRYPT_ALGO_LAST_HASH; cryptAlgo++ )
340  {
341  if( cryptStatusOK( cryptQueryCapability( cryptAlgo, &cryptQueryInfo ) ) )
342  {
343  status = testProcessing( cryptAlgo, CRYPT_UNUSED,
344  cryptQueryInfo );
345  if( cryptStatusError( status ) )
346  {
347  printf( "\nAlgorithm %d processing failed with status %d.\n",
348  cryptAlgo, status );
349  errorCount++;
350  }
351  }
352  }
353  for( cryptAlgo = CRYPT_ALGO_FIRST_MAC;
354  cryptAlgo <= CRYPT_ALGO_LAST_MAC; cryptAlgo++ )
355  {
356  if( cryptStatusOK( cryptQueryCapability( cryptAlgo, &cryptQueryInfo ) ) )
357  {
358  status = testProcessing( cryptAlgo, CRYPT_UNUSED,
359  cryptQueryInfo );
360  if( cryptStatusError( status ) )
361  {
362  printf( "\nAlgorithm %d processing failed with status %d.\n",
363  cryptAlgo, status );
364  errorCount++;
365  }
366  }
367  }
368  if( errorCount )
369  printf( "%d errors detected.\n", errorCount );
370  }
371 
372 /****************************************************************************
373 * *
374 * Kernel Check Test *
375 * *
376 ****************************************************************************/
377 
378 /* Kernel check test */
379 
380 static void smokeTestAttributes( const CRYPT_HANDLE cryptHandle )
381  {
382  int attribute;
383 
384  printf( "." );
385  for( attribute = CRYPT_ATTRIBUTE_NONE; attribute < 8000; attribute++ )
386  {
387  char buffer[ 1024 ];
388  int value;
389 
390  cryptGetAttribute( cryptHandle, attribute, &value );
391  cryptGetAttributeString( cryptHandle, attribute, buffer, &value );
392  }
393  cryptDestroyObject( cryptHandle );
394  }
395 
396 static void testKernelChecks( void )
397  {
399  int subType;
400 
401  printf( "Running kernel smoke test:\n Contexts" );
402  for( subType = 0; subType < 500; subType++ )
403  {
404  if( cryptStatusOK( cryptCreateContext( &cryptHandle, CRYPT_UNUSED,
405  subType ) ) )
406  smokeTestAttributes( cryptHandle );
407  }
408  printf( "\n Certs" );
409  for( subType = 0; subType < 500; subType++ )
410  {
411  if( cryptStatusOK( cryptCreateCert( &cryptHandle, CRYPT_UNUSED,
412  subType ) ) )
413  smokeTestAttributes( cryptHandle );
414  }
415  printf( "\n Envelopes" );
416  for( subType = 0; subType < 500; subType++ )
417  {
418  if( cryptStatusOK( cryptCreateEnvelope( &cryptHandle, CRYPT_UNUSED,
419  subType ) ) )
420  smokeTestAttributes( cryptHandle );
421  }
422  printf( "\n Sessions" );
423  for( subType = 0; subType < 500; subType++ )
424  {
425  if( cryptStatusOK( cryptCreateSession( &cryptHandle, CRYPT_UNUSED,
426  subType ) ) )
427  smokeTestAttributes( cryptHandle );
428  }
429  printf( "\n" );
430  }
431 
432 /****************************************************************************
433 * *
434 * Simple Threading Stress Test *
435 * *
436 ****************************************************************************/
437 
438 /* Multi-threaded processing stress test. In order to add a little
439  nondeterminism on single-threaded machines, we need to add some sleep()
440  calls between crypto operations. Even this isn't perfect, there's no
441  real way to guarantee that they aren't simply executed in round-robin
442  fashion with only one thread in the kernel at a time without modifying
443  the kernel to provide diagnostic info */
444 
445 #ifdef WINDOWS_THREADS
446 
447 #define NO_SIMPLE_THREADS 45
448 
449 static void randSleep( void )
450  {
451  Sleep( ( rand() % 150 ) + 1 );
452  }
453 
454 unsigned __stdcall processDataThread( void *arg )
455  {
457  BYTE buffer[ 1024 ];
458  int threadNo = ( int ) arg;
459  int status;
460 
461  randSleep();
462  memset( buffer, '*', 1024 );
463  status = cryptCreateContext( &cryptContext, CRYPT_UNUSED,
464  CRYPT_ALGO_3DES );
465  if( cryptStatusOK( status ) )
466  {
467  randSleep();
468  status = cryptSetAttributeString( cryptContext, CRYPT_CTXINFO_KEY,
469  "123456781234567812345678", 24 );
470  }
471  if( cryptStatusOK( status ) )
472  {
473  randSleep();
474  status = cryptEncrypt( cryptContext, buffer, 1024 );
475  }
476  if( cryptStatusOK( status ) )
477  {
478  randSleep();
479  status = cryptEncrypt( cryptContext, buffer, 0 );
480  }
481  if( cryptStatusOK( status ) )
482  {
483  randSleep();
484  status = cryptDestroyContext( cryptContext );
485  }
486  if( cryptStatusError( status ) )
487  printf( "\nEncryption failed with status %d.\n", status );
488  else
489  printf( "%d ", threadNo );
490 
491  _endthreadex( 0 );
492  return( 0 );
493  }
494 
495 static void testStressThreads( void )
496  {
497  HANDLE hThreadArray[ NO_SIMPLE_THREADS ];
498  int i;
499 
500  /* Start the threads */
501  for( i = 0; i < NO_SIMPLE_THREADS; i++ )
502  {
503  unsigned threadID;
504 
505  hThreadArray[ i ] = ( HANDLE ) \
506  _beginthreadex( NULL, 0, &processDataThread, ( void * ) i, 0,
507  &threadID );
508  if( hThreadArray[ i ] == 0 )
509  printf( "Thread %d couldn't be created.\n", i );
510  }
511  printf( "Threads completed: " );
512 
513  /* Wait for all the threads to complete */
514  if( WaitForMultipleObjects( NO_SIMPLE_THREADS, hThreadArray, TRUE,
515  15000 ) == WAIT_TIMEOUT )
516  puts( "\nNot all threads completed in 15s." );
517  else
518  puts( "." );
519  for( i = 0; i < NO_SIMPLE_THREADS; i++ )
520  CloseHandle( hThreadArray[ i ] );
521  }
522 #endif /* WINDOWS_THREADS */
523 
524 #if defined( UNIX_THREADS ) || defined( WINDOWS_THREADS )
525 
526 #ifdef UNIX_THREADS
527  void *envelopeDataThread( void *arg )
528 #else
529  unsigned __stdcall envelopeDataThread( void *arg )
530 #endif /* Different threading models */
531  {
532  static const char *envData = "qwertyuiopasdfghjklzxcvbnm";
533  BYTE fileBuffer[ BUFFER_SIZE ];
534  const unsigned uThread = ( unsigned ) arg;
535  const time_t startTime = time( NULL );
536  int count, status;
537 
538  printf( "Thread %d started.\n", uThread );
539  fflush( stdout );
540 
541  filenameFromTemplate( fileBuffer, CERT_FILE_TEMPLATE, 13 );
542 
543  for( count = 0; count < 150; count++ )
544  {
545  CRYPT_ENVELOPE cryptEnvelope;
546  CRYPT_CERTIFICATE cryptCert;
547  BYTE envBuffer[ BUFFER_SIZE ];
548  int bytesCopied;
549 
550  /* Create the cert and envelope and add the cert to the envelope */
551  status = importCertFile( &cryptCert, fileBuffer );
552  if( cryptStatusOK( status ) )
553  status = cryptCreateEnvelope( &cryptEnvelope, CRYPT_UNUSED,
555  if( cryptStatusOK( status ) )
556  status = cryptSetAttribute( cryptEnvelope,
557  CRYPT_ENVINFO_PUBLICKEY, cryptCert );
558  if( cryptStatusError( status ) )
559  break;
560 
561  /* Envelope data and destroy the envelope */
562  status = cryptPushData( cryptEnvelope, envData, strlen( envData ),
563  &bytesCopied );
564  if( cryptStatusOK( status ) )
565  status = cryptPushData( cryptEnvelope, NULL, 0, NULL );
566  if( cryptStatusOK( status ) )
567  status = cryptPopData( cryptEnvelope, envBuffer, BUFFER_SIZE,
568  &bytesCopied );
569  if( cryptStatusOK( status ) )
570  status = cryptDestroyEnvelope( cryptEnvelope );
571  if( cryptStatusError( status ) )
572  break;
573  printf( "%c", uThread + '0' );
574  }
575 
576  printf( "Thread %u exited after %d seconds.\n", uThread,
577  time( NULL ) - startTime );
578  fflush( stdout );
579 #ifdef UNIX_THREADS
580  pthread_exit( NULL );
581 #else
582  _endthreadex( 0 );
583 #endif /* Different threading models */
584  return( 0 );
585  }
586 
587 static void testContinuousThreads( void )
588  {
589  unsigned threadID1, threadID2;
590 #ifdef UNIX_THREADS
591  pthread_t thread1, thread2;
592 #else
593  HANDLE hThread1, hThread2;
594 #endif /* Different threading models */
595 
596  cryptAddRandom( "xyzzy", 5 );
597 #ifdef UNIX_THREADS
598  pthread_create( &thread1, NULL, envelopeDataThread, ( void * ) 1 );
599  pthread_create( &thread2, NULL, envelopeDataThread, ( void * ) 2 );
600 #else
601  hThread1 = ( HANDLE ) _beginthreadex( NULL, 0, envelopeDataThread,
602  ( void * ) 1, 0, &threadID1 );
603  hThread2 = ( HANDLE ) _beginthreadex( NULL, 0, envelopeDataThread,
604  ( void * ) 2, 0, &threadID2 );
605 #endif /* Different threading models */
606  delayThread( 30 );
607  printf( "Hit a key..." );
608  fflush( stdout );
609  getchar();
610  cryptEnd();
611  exit( EXIT_SUCCESS );
612  }
613 #endif /* UNIX_THREADS || WINDOWS_THREADS */
614 
615 /****************************************************************************
616 * *
617 * Complex Threading Stress Test *
618 * *
619 ****************************************************************************/
620 
621 /* Unlike the previous test, there's enough nondeterminism added in this one
622  that things go out of sync all by themselves */
623 
624 #ifdef WINDOWS_THREADS
625 
626 #define NO_COMPLEX_THREADS 4
627 
628 unsigned __stdcall signTest( void *arg )
629  {
630  CRYPT_KEYSET cryptKeyset;
631  CRYPT_CONTEXT privateKeyContext;
632  CRYPT_ENVELOPE cryptEnvelope;
633  BYTE buffer[ 1024 ];
634  const int count = *( ( int * ) arg );
635  int bytesCopied, i, status;
636 
637  printf( "SignTest %d.\n", count );
638 
639  for( i = 0; i < count; i++ )
640  {
641  status = cryptKeysetOpen( &cryptKeyset, CRYPT_UNUSED,
644  if( cryptStatusOK( status ) )
645  status = cryptGetPrivateKey( cryptKeyset, &privateKeyContext,
648  if( cryptStatusOK( status ) )
649  status = cryptCreateEnvelope( &cryptEnvelope, CRYPT_UNUSED,
651  if( cryptStatusOK( status ) )
652  status = cryptSetAttribute( cryptEnvelope,
654  privateKeyContext );
655  if( cryptStatusOK( status ) )
656  status = cryptPushData( cryptEnvelope, "message", 7,
657  &bytesCopied );
658  if( cryptStatusOK( status ) )
659  status = cryptFlushData( cryptEnvelope );
660  if( cryptStatusOK( status ) )
661  status = cryptPopData( cryptEnvelope, buffer, 1024,
662  &bytesCopied );
663  if( cryptStatusOK( status ) )
664  status = cryptDestroyContext( privateKeyContext );
665  if( cryptStatusOK( status ) )
666  status = cryptKeysetClose( cryptKeyset );
667  if( cryptStatusOK( status ) )
668  status = cryptDestroyEnvelope( cryptEnvelope );
669  if( cryptStatusError( status ) )
670  {
671  _endthreadex( status );
672  return( 0 );
673  }
674  }
675 
676  _endthreadex( 0 );
677  return( 0 );
678  }
679 
680 unsigned __stdcall encTest( void *arg )
681  {
682  CRYPT_ENVELOPE cryptEnvelope;
683  CRYPT_CERTIFICATE cryptCert;
684  BYTE buffer[ 1024 ];
685  const int count = *( ( int * ) arg );
686  int bytesCopied, i, status;
687 
688  printf( "EncTest %d.\n", count );
689 
690  for( i = 0; i < count; i++ )
691  {
692  FILE *filePtr;
693  int certSize;
694 
695  if( ( filePtr = fopen( "testdata/cert5.der", "rb" ) ) != NULL )
696  {
697  certSize = fread( buffer, 1, 1024, filePtr );
698  fclose( filePtr );
699  }
700 
701  status = cryptImportCert( buffer, certSize, CRYPT_UNUSED,
702  &certificate );
703  if( cryptStatusOK( status ) )
704  status = cryptCreateEnvelope( &cryptEnvelope, CRYPT_UNUSED,
706  if( cryptStatusOK( status ) )
707  status = cryptSetAttribute( cryptEnvelope,
708  CRYPT_ENVINFO_PUBLICKEY, cryptCert );
709  if( cryptStatusOK( status ) )
710  status = cryptPushData( cryptEnvelope, buffer, 200,
711  &bytesCopied );
712  if( cryptStatusOK( status ) )
713  status = cryptFlushData( cryptEnvelope );
714  if( cryptStatusOK( status ) )
715  status = cryptPopData( cryptEnvelope, buffer, 1024,
716  &bytesCopied );
717  if( cryptStatusOK( status ) )
718  status = cryptDestroyCert( cryptCert );
719  if( cryptStatusOK( status ) )
720  status = cryptDestroyEnvelope( cryptEnvelope );
721  if( cryptStatusError( status ) )
722  {
723  _endthreadex( status );
724  return( 0 );
725  }
726  }
727 
728  _endthreadex( 0 );
729  return( 0 );
730  }
731 
732 int testStressThreadsComplex( void )
733  {
734  HANDLE hThreads[ NO_COMPLEX_THREADS ];
735  int i;
736 
738 
739  for( i = 0; i < 1000; i++ )
740  {
741  unsigned dwThreadId;
742  int j;
743 
744  hThreads[ 0 ] = ( HANDLE ) \
745  _beginthreadex( NULL, 0, encTest, &i, 0, &dwThreadId );
746  hThreads[ 1 ] = ( HANDLE ) \
747  _beginthreadex( NULL, 0, signTest, &i, 0, &dwThreadId );
748  hThreads[ 2 ] = ( HANDLE ) \
749  _beginthreadex( NULL, 0, encTest, &i, 0, &dwThreadId );
750  hThreads[ 3 ] = ( HANDLE ) \
751  _beginthreadex( NULL, 0, signTest, &i, 0, &dwThreadId );
752 
753  WaitForMultipleObjects( NO_COMPLEX_THREADS, hThreads, TRUE,
754  INFINITE );
755 
756  for( j = 0; j < NO_COMPLEX_THREADS; j++ )
757  CloseHandle( hThreads[ j ] );
758  }
759 
760  return 0;
761  }
762 #endif /* WINDOWS_THREADS */
763 
764 /****************************************************************************
765 * *
766 * Test Interface *
767 * *
768 ****************************************************************************/
769 
770 void smokeTest( void )
771  {
772  testDataProcessing();
773  testKernelChecks();
774  testStressObjects();
775 #if defined( UNIX_THREADS ) || defined( WINDOWS_THREADS )
776  testStressThreadsSimple();
777  testStressThreadsComplex();
778 #endif /* UNIX_THREADS || WINDOWS_THREADS */
779  }
780 #endif /* SMOKE_TEST */