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