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