1 /****************************************************************************
2 *																			*
3 *								cryptlib Test Code							*
4 *						Copyright Peter Gutmann 1995-2015					*
5 *																			*
6 ****************************************************************************/
7 
8 #if defined( __Nucleus__ )
9   #include <nu_ctype.h>
10   #include <nu_string.h>
11 #else
12   #include <ctype.h>	/* For toupper() */
13 #endif /* OS-specific includes */
14 
15 #include "cryptlib.h"
16 #include "test/test.h"
17 
18 #if defined( __MVS__ ) || defined( __VMCMS__ )
19   /* Suspend conversion of literals to ASCII. */
20   #pragma convlit( suspend )
21 #endif /* IBM big iron */
22 #if defined( __ILEC400__ )
23   #pragma convert( 0 )
24 #endif /* IBM medium iron */
25 
26 /* Optionally include and activate the Visual Leak Detector library if
27    we're running a debug build under VC++ 6.0.  Note that this can't be
28    run at the same time as Bounds Checker, since the two interefere with
29    each other */
30 
31 #if defined( _MSC_VER ) && ( _MSC_VER == 1200 ) && 0
32   #include "binaries/vld.h"
33 #endif /* VC++ 6.0 */
34 
35 /* Microsoft broke the VS 2015 runtime libraries by moving some functions
36    inline, which results in compile problems when linking to the ODBC libs,
37    which call functions that aren't externally visible any more due to
38    inlining.  To fix this, we have to implicitly add
39    legacy_stdio_definitions.lib to avoid link errors with the ODBC libs */
40 
41 #if defined( _MSC_VER ) && ( _MSC_VER == 1900 )
42   #pragma comment( lib, "legacy_stdio_definitions.lib" )
43 #endif /* VS 2015 */
44 
45 /* Optionally include the Intel Thread Checker API to control analysis */
46 
47 #if defined( _MSC_VER ) && ( _MSC_VER == 1200 ) && 0
48   #define USE_TCHECK
49   #include "../../../Intel/VTune/tcheck/Include/libittnotify.h"
50   #include "../../../Intel/VTune/Analyzer/Include/VtuneApi.h"
51   #pragma comment( lib, "C:/Program Files/Intel/VTune/Analyzer/Lib/libittnotify.lib" )
52   #pragma comment( lib, "C:/Program Files/Intel/VTune/Analyzer/Lib/VtuneApi.lib " )
53   #define THREAD_DEBUG_SUSPEND()	__itt_pause(); VTPause()
54   #define THREAD_DEBUG_RESUME()		VTResume(); __itt_resume()
55 #else
56   #define THREAD_DEBUG_SUSPEND()
57   #define THREAD_DEBUG_RESUME()
58 #endif /* VC++ 6.0 with Intel Thread Checker */
59 
60 /* Warn about nonstandard build options */
61 
62 #if defined( CONFIG_SUITEB_TESTS ) && ( defined( _MSC_VER ) || defined( __GNUC__ ) )
63   #pragma message( "  Building Suite B command-line test configuration." )
64 #endif /* CONFIG_SUITEB_TESTS with VC++/gcc */
65 
66 /* Whether various keyset tests worked, the results are used later to test
67    other routines.  We initially set the key read result to TRUE in case the
68    keyset read tests are never called, so we can still trying reading the
69    keys in other tests */
70 
71 int keyReadOK = TRUE, doubleCertOK = FALSE;
72 
73 /* The output stream to which diagnostic output is sent */
74 
75 FILE *outputStream;
76 
77 /* There are some sizeable (for DOS) data structures used, so we increase the
78    stack size to allow for them */
79 
80 #if defined( __MSDOS16__ ) && defined( __TURBOC__ )
81   extern unsigned _stklen = 16384;
82 #endif /* __MSDOS16__ && __TURBOC__ */
83 
84 /* Prototypes for general debug routines used to evaluate problems with certs
85    and envelopes from other apps */
86 
87 int xxxCertImport( const char *fileName );
88 int xxxCertCheck( const char *certFileName, const char *caFileNameOpt );
89 void xxxPubKeyRead( const char *fileName, const char *keyName );
90 void xxxPrivKeyRead( const char *fileName, const char *keyName, const char *password );
91 void xxxDataImport( const char *fileName );
92 void xxxSignedDataImport( const char *fileName );
93 void xxxEncryptedDataImport( const char *fileName, const char *keyset,
94 							 const char *password );
95 
96 /* Prototype for custom key-creation routines */
97 
98 int createTestKeys( void );
99 
100 /* Prototype for stress test interface routine */
101 
102 void smokeTest( void );
103 
104 /* Prototype for Suite B test entry point */
105 
106 #if defined( CONFIG_SUITEB_TESTS )
107 
108 int suiteBMain( int argc, char **argv );
109 
110 #endif /* CONFIG_SUITEB_TESTS */
111 
112 /****************************************************************************
113 *																			*
114 *								Utility Routines							*
115 *																			*
116 ****************************************************************************/
117 
118 /* The pseudo-CLI VC++ output windows are closed when the program exits so
119    we have to explicitly wait to allow the user to read them */
120 
121 #if defined( __WINDOWS__ ) && !defined( NDEBUG )
122 
cleanExit(const int exitStatus)123 static void cleanExit( const int exitStatus )
124 	{
125 	puts( "\nHit a key..." );
126 	getchar();
127 	exit( exitStatus );
128 	}
cleanupAndExit(const int exitStatus)129 static void cleanupAndExit( const int exitStatus )
130 	{
131 	int status;
132 
133 	status = cryptEnd();
134 	if( status == CRYPT_ERROR_INCOMPLETE )
135 		puts( "cryptEnd() failed with CRYPT_ERROR_INCOMPLETE." );
136 	cleanExit( exitStatus );
137 	}
138 #else
139 
cleanExit(const int exitStatus)140 static void cleanExit( const int exitStatus )
141 	{
142 	exit( exitStatus );
143 	}
cleanupAndExit(const int exitStatus)144 static void cleanupAndExit( const int exitStatus )
145 	{
146 	cryptEnd();
147 	cleanExit( exitStatus );
148 	}
149 #endif /* __WINDOWS__ && !NDEBUG */
150 
151 /* Update the cryptlib config file.  This code can be used to set the
152    information required to load PKCS #11 device drivers:
153 
154 	- Set the driver path in the CRYPT_OPTION_DEVICE_PKCS11_DVR01 setting
155 	  below.
156 	- Add a call to updateConfig() from somewhere (e.g.the test kludge function).
157 	- Run the test code until it calls updateConfig().
158 	- Remove the updateConfig() call, then run the test code as normal.
159 	  The testDevices() call will report the results of trying to use your
160 	  driver.
161 
162   cryptlib's SafeLoadLibrary() will always load drivers from the Windows
163   system directory / %SystemDirectory% unless given an absolute path */
164 
updateConfig(void)165 static void updateConfig( void )
166 	{
167 #if 0
168 	const char *driverPath = "acospkcs11.dll";		/* ACOS */
169 	const char *driverPath = "aetpkss1.dll";		/* AET */
170 	const char *driverPath = "aloaha_pkcs11.dll";	/* Aloaha */
171 	const char *driverPath = "etpkcs11.dll";		/* Aladdin eToken */
172 	const char *driverPath = "psepkcs11.dll";		/* A-Sign */
173 	const char *driverPath = "asepkcs.dll";			/* Athena */
174 	const char *driverPath = "c:/temp/bpkcs11.dll";	/* Bloomberg */
175 	const char *driverPath = "opensc-pkcs11.dll";	/* CardContact (via OpenSC) under Windows */
176 	const char *driverPath = "/usr/lib/opensc-pkcs11.so";	/* CardContact (OpenSC) under Linux */
177 	const char *driverPath = "cryst32.dll";			/* Chrysalis */
178 	const char *driverPath = "c:/program files/luna/cryst201.dll";	/* Chrysalis */
179 	const char *driverPath = "pkcs201n.dll";		/* Datakey */
180 	const char *driverPath = "dkck201.dll";			/* Datakey (for Entrust) */
181 	const char *driverPath = "dkck232.dll";			/* Datakey/iKey (NB: buggy, use 201) */
182 	const char *driverPath = "c:/program files/eracom/cprov sw/cryptoki.dll";	/* Eracom (old, OK) */
183 	const char *driverPath = "c:/program files/eracom/cprov runtime/cryptoki.dll";	/* Eracom (new, doesn't work) */
184 	const char *driverPath = "sadaptor.dll";		/* Eutron */
185 	const char *driverPath = "ngp11v211.dll";		/* Feitian Technology */
186 	const char *driverPath = "pk2priv.dll";			/* Gemplus */
187 	const char *driverPath = "c:/program files/gemplus/gclib.dll";	/* Gemplus */
188 	const char *driverPath = "cryptoki.dll";		/* IBM */
189 	const char *driverPath = "csspkcs11.dll";		/* IBM */
190 	const char *driverPath = "ibmpkcss.dll";		/* IBM */
191 	const char *driverPath = "id2cbox.dll";			/* ID2 */
192 	const char *driverPath = "cknfast.dll";			/* nCipher */
193 	const char *driverPath = "/opt/nfast/toolkits/pkcs11/libcknfast.so";/* nCipher under Unix */
194 	const char *driverPath = "/usr/lib/libcknfast.so";	/* nCipher under Unix */
195 	const char *driverPath = "c:/program files/mozilla firefox/softokn3.dll";/* Netscape */
196 	const char *driverPath = "nxpkcs11.dll";		/* Nexus */
197 	const char *driverPath = "AuCryptoki2-0.dll";	/* Oberthur */
198 	const char *driverPath = "opensc-pkcs11.dll";	/* OpenSC */
199 	const char *driverPath = "micardoPKCS11.dll";	/* Orga Micardo */
200 	const char *driverPath = "cryptoki22.dll";		/* Rainbow HSM (for USB use Datakey dvr) */
201 	const char *driverPath = "p11card.dll";			/* Safelayer HSM (for USB use Datakey dvr) */
202 	const char *driverPath = "slbck.dll";			/* Schlumberger */
203 	const char *driverPath = "SetTokI.dll";			/* SeTec */
204 	const char *driverPath = "siecap11.dll";		/* Siemens */
205 	const char *driverPath = "smartp11.dll";		/* SmartTrust */
206 	const char *driverPath = "SpyPK11.dll";			/* Spyrus */
207 #endif /* 0 */
208 //	const char *driverPath = "c:/program files/eracom/cprov sw/cryptoki.dll";	/* Eracom (old, OK) */
209 	const char *driverPath = "opensc-pkcs11.dll";	/* CardContact (via OpenSC) */
210 	int status;
211 
212 	printf( "Updating cryptlib configuration to load PKCS #11 driver\n  "
213 			"'%s' as default driver...", driverPath );
214 
215 	/* Set the path for a PKCS #11 device driver.  We only enable one of
216 	   these at a time to speed the startup time */
217 	status = cryptSetAttributeString( CRYPT_UNUSED,
218 									  CRYPT_OPTION_DEVICE_PKCS11_DVR01,
219 									  driverPath, strlen( driverPath ) );
220 	if( cryptStatusError( status ) )
221 		{
222 		printf( "\n\nError updating PKCS #11 device driver profile, "
223 				"status %d.\n", status );
224 		cleanupAndExit( EXIT_FAILURE );
225 		}
226 
227 	/* Flush the updated options to disk */
228 	status = cryptSetAttribute( CRYPT_UNUSED, CRYPT_OPTION_CONFIGCHANGED,
229 								FALSE );
230 	if( cryptStatusError( status ) )
231 		{
232 		printf( "\n\nError comitting device driver profile update to disk, "
233 				"status %d.\n", status );
234 		cleanupAndExit( EXIT_FAILURE );
235 		}
236 
237 	puts( " done.\n" );
238 	cleanupAndExit( EXIT_SUCCESS );
239 	}
240 
241 /* Add trusted certs to the config file and make sure that they're
242    persistent.  This can't be done in the normal self-test since it requires
243    that cryptlib be restarted as part of the test to re-read the config file,
244    and because it modifies the cryptlib config file */
245 
updateConfigCert(void)246 static void updateConfigCert( void )
247 	{
248 	CRYPT_CERTIFICATE trustedCert;
249 	int status;
250 
251 	/* Import the first certificate, make it trusted, and commit the changes */
252 	importCertFromTemplate( &trustedCert, CERT_FILE_TEMPLATE, 1 );
253 	cryptSetAttribute( trustedCert, CRYPT_CERTINFO_TRUSTED_IMPLICIT, TRUE );
254 	cryptSetAttribute( CRYPT_UNUSED, CRYPT_OPTION_CONFIGCHANGED, FALSE );
255 	cryptDestroyCert( trustedCert );
256 	cryptEnd();
257 
258 	/* Do the same with a second certificate.  At the conclusion of this, we
259 	   should have two trusted certificates on disk */
260 	status = cryptInit();
261 	if( cryptStatusError( status ) )
262 		{
263 		puts( "Couldn't reload cryptlib configuration." );
264 		return;
265 		}
266 	importCertFromTemplate( &trustedCert, CERT_FILE_TEMPLATE, 2 );
267 	cryptSetAttribute( trustedCert, CRYPT_CERTINFO_TRUSTED_IMPLICIT, TRUE );
268 	cryptSetAttribute( CRYPT_UNUSED, CRYPT_OPTION_CONFIGCHANGED, FALSE );
269 	cryptDestroyCert( trustedCert );
270 	cryptEnd();
271 	}
272 
273 /****************************************************************************
274 *																			*
275 *								Argument Processing							*
276 *																			*
277 ****************************************************************************/
278 
279 /* Flags for the tests that we want to perform */
280 
281 #define DO_SELFTEST				0x0001
282 #define DO_LOWLEVEL				0x0002
283 #define DO_RANDOM				0x0004
284 #define DO_CONFIG				0x0008
285 #define DO_DEVICE				0x0010
286 #define DO_MIDLEVEL				0x0020
287 #define DO_CERT					0x0040
288 #define DO_KEYSETFILE			0x0080
289 #define DO_KEYSETDBX			0x0100
290 #define DO_CERTPROCESS			0x0200
291 #define DO_HIGHLEVEL			0x0400
292 #define DO_ENVELOPE				0x0800
293 #define DO_SESSION				0x1000
294 #define DO_SESSIONLOOPBACK		0x2000
295 #define DO_USER					0x4000
296 
297 #define DO_ALL					0xFFFF
298 
299 /* Show usage and exit */
300 
usageExit(void)301 static void usageExit( void )
302 	{
303 	puts( "Usage: testlib [-bcdefhiklmoprstu]" );
304 
305 	puts( "  Encryption function tests:" );
306 	puts( "       -l = Test low-level functions" );
307 	puts( "       -m = Test mid-level functions" );
308 	puts( "       -i = Test high-level functions" );
309 	puts( "" );
310 
311 	puts( "  Subsystem tests:" );
312 	puts( "       -c = Test certificate subsystem" );
313 	puts( "       -d = Test device subsystem" );
314 	puts( "       -f = Test file keyset subsystem" );
315 	puts( "       -k = Test database keyset subsystem" );
316 	puts( "       -e = Test envelope subsystem" );
317 	puts( "       -s = Test session subsystem" );
318 	puts( "       -t = Test session subsystem via loopback interface" );
319 	puts( "       -u = Test user subsystem" );
320 	puts( "" );
321 
322 	puts( "  Miscellaneous tests:" );
323 	puts( "       -r = Test entropy-gathering routines" );
324 	puts( "       -b = Perform built-in self-test" );
325 	puts( "       -o = Test configuration management routines" );
326 	puts( "       -p = Test certificate processing" );
327 	puts( "" );
328 
329 	puts( "  Other options:" );
330 	puts( "       -h = Display this help text" );
331 	puts( "       -- = End of arg list" );
332 	puts( "" );
333 
334 	puts( "Default is to test all cryptlib subsystems." );
335 	exit( EXIT_FAILURE );
336 	}
337 
338 /* Process command-line arguments */
339 
processArgs(int argc,char ** argv,int * argFlags,const char ** zCmdPtrPtr,const char ** zArgPtrPtr)340 static int processArgs( int argc, char **argv, int *argFlags,
341 						const char **zCmdPtrPtr, const char **zArgPtrPtr )
342 	{
343 	const char *zargPtr = NULL;
344 	BOOLEAN moreArgs = TRUE, isZArg = FALSE;
345 
346 	/* Clear return values */
347 	*argFlags = 0;
348 	*zCmdPtrPtr = *zArgPtrPtr = NULL;
349 
350 	/* No args means test everything */
351 	if( argc <= 0 )
352 		{
353 		*argFlags = DO_ALL;
354 
355 		return( TRUE );
356 		}
357 
358 	/* Check for arguments */
359 	while( argc > 0 && ( *argv[ 0 ] == '-' || isZArg ) && moreArgs )
360 		{
361 		const char *argPtr = argv[ 0 ] + 1;
362 
363 		/* If the last argument was a -z one, this is the argument value
364 		   that goes with it */
365 		if( isZArg )
366 			{
367 			isZArg = FALSE;
368 			*zArgPtrPtr = argv[ 0 ];
369 			argv++;
370 			argc--;
371 			continue;
372 			}
373 
374 		while( *argPtr )
375 			{
376 			switch( toupper( *argPtr ) )
377 				{
378 				case '-':
379 					moreArgs = FALSE;	/* GNU-style end-of-args flag */
380 					break;
381 
382 				case 'B':
383 					*argFlags |= DO_SELFTEST;
384 					break;
385 
386 				case 'C':
387 					*argFlags |= DO_CERT;
388 					break;
389 
390 				case 'D':
391 					*argFlags |= DO_DEVICE;
392 					break;
393 
394 				case 'E':
395 					*argFlags |= DO_ENVELOPE;
396 					break;
397 
398 				case 'F':
399 					*argFlags |= DO_KEYSETFILE;
400 					break;
401 
402 				case 'H':
403 					usageExit();
404 					break;
405 
406 				case 'I':
407 					*argFlags |= DO_HIGHLEVEL;
408 					break;
409 
410 				case 'K':
411 					*argFlags |= DO_KEYSETDBX;
412 					break;
413 
414 				case 'L':
415 					*argFlags |= DO_LOWLEVEL;
416 					break;
417 
418 				case 'M':
419 					*argFlags |= DO_MIDLEVEL;
420 					break;
421 
422 				case 'O':
423 					*argFlags |= DO_CONFIG;
424 					break;
425 
426 				case 'P':
427 					*argFlags |= DO_CERTPROCESS;
428 					break;
429 
430 				case 'R':
431 					*argFlags |= DO_RANDOM;
432 					break;
433 
434 				case 'S':
435 					*argFlags |= DO_SESSION;
436 					break;
437 
438 				case 'T':
439 					*argFlags |= DO_SESSIONLOOPBACK;
440 					break;
441 
442 				case 'U':
443 					*argFlags |= DO_USER;
444 					break;
445 
446 				case 'Z':
447 					zargPtr = argPtr + 1;
448 					if( *zargPtr == '\0' )
449 						{
450 						puts( "Error: Missing argument for -z option." );
451 						return( FALSE );
452 						}
453 					while( argPtr[ 1 ] )
454 						argPtr++;	/* Skip rest of arg */
455 					*zCmdPtrPtr = zargPtr;
456 					isZArg = TRUE;
457 					break;
458 
459 				default:
460 					printf( "Error: Unknown argument '%c'.\n", *argPtr );
461 					return( FALSE );
462 				}
463 			argPtr++;
464 			}
465 		argv++;
466 		argc--;
467 		}
468 	if( argc > 0 )
469 		{
470 		printf( "Error: Unknown argument '%s'.\n", argv[ 0 ] );
471 		return( FALSE );
472 		}
473 
474 	return( TRUE );
475 	}
476 
477 /****************************************************************************
478 *																			*
479 *								Fuzzing Wrapper								*
480 *																			*
481 ****************************************************************************/
482 
483 /* Wrapper for injecting fuzz data */
484 
485 //#define CONFIG_FUZZ
486 
487 #if defined( CONFIG_FUZZ ) && !defined( NDEBUG )
488 
489 void __afl_manual_init( void );
490 
fuzzSession(const CRYPT_SESSION_TYPE sessionType,const char * fuzzFileName)491 static int fuzzSession( const CRYPT_SESSION_TYPE sessionType,
492 						const char *fuzzFileName )
493 	{
494 	CRYPT_SESSION cryptSession;
495 	CRYPT_CONTEXT cryptPrivKey = CRYPT_UNUSED;
496 	BYTE buffer[ 4096 ];
497 	const BOOLEAN isServer = \
498 			( sessionType == CRYPT_SESSION_SSH_SERVER || \
499 			  sessionType == CRYPT_SESSION_SSL_SERVER || \
500 			  sessionType == CRYPT_SESSION_OCSP_SERVER || \
501 			  sessionType == CRYPT_SESSION_RTCS_SERVER || \
502 			  sessionType == CRYPT_SESSION_TSP_SERVER || \
503 			  sessionType == CRYPT_SESSION_CMP_SERVER || \
504 			  sessionType == CRYPT_SESSION_SCEP_SERVER ) ? \
505 			TRUE : FALSE;
506 	int length, status;
507 
508 	/* Create the session */
509 	status = cryptCreateSession( &cryptSession, CRYPT_UNUSED, sessionType );
510 	if( cryptStatusError( status ) )
511 		return( status );
512 
513 	/* Set up the various attributes needed to establish a minimal session */
514 	if( !isServer )
515 		{
516 		status = cryptSetAttributeString( cryptSession,
517 										  CRYPT_SESSINFO_SERVER_NAME,
518 										  "localhost", 9 );
519 		if( cryptStatusError( status ) )
520 			return( status );
521 		}
522 	if( isServer )
523 		{
524 		if( !loadRSAContexts( CRYPT_UNUSED, NULL, &cryptPrivKey ) )
525 			return( CRYPT_ERROR_FAILED );
526 		}
527 	if( sessionType == CRYPT_SESSION_SSH || \
528 		sessionType == CRYPT_SESSION_CMP )
529 		{
530 		status = cryptSetAttributeString( cryptSession,
531 										  CRYPT_SESSINFO_USERNAME,
532 										  SSH_USER_NAME,
533 										  paramStrlen( SSH_USER_NAME ) );
534 		if( cryptStatusOK( status ) )
535 			{
536 			status = cryptSetAttributeString( cryptSession,
537 											  CRYPT_SESSINFO_PASSWORD,
538 											  SSH_PASSWORD,
539 											  paramStrlen( SSH_PASSWORD ) );
540 			}
541 		if( cryptStatusError( status ) )
542 			return( status );
543 		}
544 	if( sessionType == CRYPT_SESSION_CMP )
545 		{
546 		status = cryptSetAttribute( cryptSession,
547 									CRYPT_SESSINFO_CMP_REQUESTTYPE,
548 									CRYPT_REQUESTTYPE_INITIALISATION );
549 		if( cryptStatusError( status ) )
550 			return( status );
551 		}
552 
553 	/* Perform any final session initialisation */
554 	cryptFuzzInit( cryptSession, cryptPrivKey );
555 
556 	/* We're ready to go, start the forkserver and read the mutable data */
557 #ifndef __WINDOWS__
558 	__afl_manual_init();
559 #endif /* !__WINDOWS__ */
560 	length = readFileData( fuzzFileName, fuzzFileName, buffer, 4096, 32,
561 						   TRUE );
562 	if( length < 32 )
563 		return( CRYPT_ERROR_READ );
564 
565 	/* Perform the fuzzing */
566 	( void ) cryptSetFuzzData( cryptSession, buffer, length );
567 	cryptDestroySession( cryptSession );
568 	if( cryptPrivKey != CRYPT_UNUSED )
569 		cryptDestroyContext( cryptPrivKey );
570 
571 	return( CRYPT_OK );
572 	}
573 
fuzzFile(const char * fuzzFileName)574 static int fuzzFile( const char *fuzzFileName )
575 	{
576 	CRYPT_CERTIFICATE cryptCert;
577 	BYTE buffer[ 4096 ];
578 	int length, status;
579 
580 	/* Read the data to fuzz */
581 	length = readFileData( fuzzFileName, fuzzFileName, buffer, 4096, 64,
582 						   TRUE );
583 	if( length < 64 )
584 		return( CRYPT_ERROR_READ );
585 
586 	/* Process the input file */
587 	status = cryptImportCert( buffer, length, CRYPT_UNUSED, &cryptCert );
588 	if( cryptStatusOK( status ) )
589 		cryptDestroyCert( cryptCert );
590 
591 	return( CRYPT_OK );
592 	}
593 
fuzzEnvelope(const char * fuzzFileName)594 static int fuzzEnvelope( const char *fuzzFileName )
595 	{
596 	CRYPT_ENVELOPE cryptEnvelope;
597 	BYTE buffer[ 4096 ];
598 	int length, bytesIn, status;
599 
600 	/* Create the envelope */
601 	status = cryptCreateEnvelope( &cryptEnvelope, CRYPT_UNUSED,
602 								  CRYPT_FORMAT_AUTO );
603 	if( cryptStatusError( status ) )
604 		return( status );
605 
606 	/* We're ready to go, start the forkserver and read the mutable data */
607 #ifndef __WINDOWS__
608 	__afl_manual_init();
609 #endif /* !__WINDOWS__ */
610 	length = readFileData( fuzzFileName, fuzzFileName, buffer, 4096, 64,
611 						   TRUE );
612 	if( length < 64 )
613 		return( CRYPT_ERROR_READ );
614 
615 	/* Process the input file */
616 	( void ) cryptPushData( cryptEnvelope, buffer, length, &bytesIn );
617 	cryptDestroyEnvelope( cryptEnvelope );
618 
619 	return( CRYPT_OK );
620 	}
621 
fuzzKeyset(const char * fuzzFileName)622 static int fuzzKeyset( const char *fuzzFileName )
623 	{
624 	CRYPT_KEYSET cryptKeyset;
625 	int status;
626 
627 	/* Start the forkserver */
628 #ifndef __WINDOWS__
629 	__afl_manual_init();
630 #endif /* !__WINDOWS__ */
631 
632 	/* Process the input file */
633 	status = cryptKeysetOpen( &cryptKeyset, CRYPT_UNUSED, CRYPT_KEYSET_FILE,
634 							  fuzzFileName, CRYPT_KEYOPT_READONLY );
635 	if( cryptStatusOK( status ) )
636 		cryptKeysetClose( cryptKeyset );
637 
638 	return( CRYPT_OK );
639 	}
640 
fuzzSpecial(const int fuzzType,const char * fuzzFileName)641 static int fuzzSpecial( const int fuzzType, const char *fuzzFileName )
642 	{
643 	CRYPT_CONTEXT cryptPrivKey;
644 	BYTE buffer[ 8192 ];
645 	const int minLength = ( fuzzType == 4000 ) ? 2 : 16;
646 	int length, status;
647 
648 	/* If we're fuzzing bignum ops, load the private key that we'll need */
649 	if( fuzzType == 4000 )
650 		{
651 		if( !loadRSAContexts( CRYPT_UNUSED, NULL, &cryptPrivKey ) )
652 			return( CRYPT_ERROR_FAILED );
653 		}
654 
655 	/* We're ready to go, start the forkserver and read the mutable data */
656 #ifndef __WINDOWS__
657 	__afl_manual_init();
658 #endif /* !__WINDOWS__ */
659 	length = readFileData( fuzzFileName, fuzzFileName, buffer, 8192,
660 						   minLength, TRUE );
661 	if( length < minLength )
662 		return( CRYPT_ERROR_READ );
663 
664 	/* Process the input file */
665 	if( fuzzType == 4000 )
666 		{
667 		BYTE tmpBuffer[ 8192 ];
668 
669 #if 0	/* We don't do an early-out in order to check that the bignum code
670 		   can actually reject all invalid input values */
671 		/* Any value that's larger than the modulus will be trivially
672 		   rejected so there's no point in trying to process it */
673 		if( buffer[ 0 ] > 0x9C )
674 			{
675 			cryptDestroyContext( cryptPrivKey );
676 			return( CRYPT_OK );
677 			}
678 #endif /* 0 */
679 
680 		memcpy( tmpBuffer, buffer, length );
681 		status = cryptDecrypt( cryptPrivKey, buffer, length );
682 		if( cryptStatusOK( status ) )
683 			status = cryptEncrypt( cryptPrivKey, buffer, length );
684 		if( cryptStatusOK( status ) )
685 			{
686 			/* Make sure that we got back what we started with */
687 			assert( !memcmp( buffer, tmpBuffer, length ) );
688 			}
689 		cryptDestroyContext( cryptPrivKey );
690 		}
691 	else
692 		{
693 		( void ) cryptFuzzSpecial( CRYPT_UNUSED, buffer, length,
694 								   ( fuzzType == 4000 ) ? TRUE : FALSE );
695 		}
696 
697 	return( CRYPT_OK );
698 	}
699 
fuzz(const char * cmd,const char * arg)700 static int fuzz( const char *cmd, const char *arg )
701 	{
702 	static const struct {
703 		const char *fuzzTypeName;
704 		const int fuzzType;
705 		} fuzzTypeMap[] = {
706 		{ "base64", 1000 }, { "certificate", 1001 },
707 		{ "certchain", 1002 }, { "certreq", 1002 },
708 		{ "cms", 2000 }, { "pgp", 2001 },
709 		{ "pkcs12", 3000 }, { "pkcs15", 3001 },
710 		{ "pgppub", 3002 }, { "pgpsec", 3003 },
711 		{ "bignum", 4000 }, { "http-req", 4001 },
712 		{ "http-resp", 4002 },
713 		{ "ssh-client", CRYPT_SESSION_SSH },
714 		{ "ssh-server", CRYPT_SESSION_SSH_SERVER },
715 		{ "ssl-client", CRYPT_SESSION_SSL },
716 		{ "ssl-server", CRYPT_SESSION_SSL_SERVER },
717 		{ "ocsp-client", CRYPT_SESSION_OCSP },
718 		{ "ocsp-server", CRYPT_SESSION_OCSP_SERVER },
719 		{ "rtcs-client", CRYPT_SESSION_RTCS },
720 		{ "rtcs-server", CRYPT_SESSION_RTCS_SERVER },
721 		{ "tsp-client", CRYPT_SESSION_TSP },
722 		{ "tsp-server", CRYPT_SESSION_TSP_SERVER },
723 		{ "scep-client", CRYPT_SESSION_SCEP },
724 		{ "scep-server", CRYPT_SESSION_SCEP_SERVER },
725 		{ "cmp-client", CRYPT_SESSION_CMP },
726 		{ "cmp-server", CRYPT_SESSION_CMP_SERVER },
727 		{ NULL, 0 }
728 		};
729 	int i, fuzzType = -1, status;
730 
731 	/* Test harness for code checking */
732 #if defined( CONFIG_FUZZ ) && !defined( NDEBUG ) && defined( __WINDOWS__ ) && 1
733 //	cmd = "base64"; arg = "test/fuzz/base64.dat";
734 //	cmd = "certificate"; arg = "test/fuzz/certificate.dat";
735 //	cmd = "certchain"; arg = "test/fuzz/certchain.dat";
736 //	cmd = "certreq"; arg = "test/fuzz/certreq.dat";
737 //	cmd = "cms"; arg = "test/fuzz/cms.dat";
738 //	cmd = "pgp"; arg = "test/fuzz/pgp.dat";
739 //	cmd = "pkcs12"; arg = "test/fuzz/pkcs12.dat";
740 //	cmd = "pkcs15"; arg = "test/fuzz/pkcs15.dat";
741 //	arg = "pgppub"; arg = "test/fuzz/pgppub.dat";
742 //	arg = "pgpsec"; arg = "test/fuzz/pgpsec.dat";
743 //	cmd = "ssl-client"; arg = "test/fuzz/ssl_svr.dat";
744 //	cmd = "ssl-server"; arg = "test/fuzz/ssl_cli.dat";
745 //	cmd = "ssh-client"; arg = "test/fuzz/ssh_svr.dat";
746 //	cmd = "ssh-server"; arg = "test/fuzz/ssh_cli.dat";
747 //	cmd = "ocsp-client"; arg = "test/fuzz/ocsp_svr.dat";
748 //	cmd = "ocsp-server"; arg = "test/fuzz/ocsp_cli.dat";
749 //	cmd = "tsp-client"; arg = "test/fuzz/tsp_svr.dat";
750 //	cmd = "tsp-server"; arg = "test/fuzz/tsp_cli.dat";
751 //	cmd = "cmp-client"; arg = "test/fuzz/cmp_svr.dat";
752 //	cmd = "cmp-server"; arg = "test/fuzz/cmp_cli.dat";
753 //	cmd = "scep-client"; cmd = "scep-server"; See comments above
754 	cmd = "bignum"; arg = "test/fuzz/bignum.dat";
755 //	cmd = "http-req"; arg = "test/fuzz/http_req.dat";
756 //	cmd = "http-resp"; arg = "test/fuzz/http_resp.dat";
757 #endif /* __WINDOWS__ test */
758 
759 	/* Make sure that we've got an input arg */
760 	if( cmd == NULL )
761 		{
762 		printf( "Error: Missing argument fuzz type.\n" );
763 		exit( EXIT_FAILURE );
764 		}
765 	if( arg == NULL )
766 		{
767 		printf( "Error: Missing argument fuzz filename.\n" );
768 		exit( EXIT_FAILURE );
769 		}
770 
771 	/* Figure out which type of fuzzing we're doing */
772 	for( i = 0; fuzzTypeMap[ i ].fuzzTypeName != NULL; i++ )
773 		{
774 		if( !strcmp( fuzzTypeMap[ i ].fuzzTypeName, cmd ) )
775 			{
776 			fuzzType = fuzzTypeMap[ i ].fuzzType;
777 			break;
778 			}
779 		}
780 	if( fuzzType == -1 )
781 		{
782 		printf( "Error: Invalid fuzz type '%s'.\n", cmd );
783 		exit( EXIT_FAILURE );
784 		}
785 	if( fuzzType == CRYPT_SESSION_SCEP || \
786 		fuzzType == CRYPT_SESSION_SCEP_SERVER )
787 		{
788 		/* SCEP uses CMS envelopes, which are already handled directly by
789 		   the envelope fuzzing.  In addition SCEP clients need to decrypt
790 		   CMS messages returned by the server, encrypted to the certificate
791 		   that they've just generated, which can't be emulated with static
792 		   data */
793 		printf( "Error: SCEP uses CMS messages which are fuzzed via "
794 				"envelopes.\n" );
795 		exit( EXIT_FAILURE );
796 		}
797 
798 	/* Fake out the randomness polling */
799 	cryptAddRandom( "xyzzy", 5 );
800 
801 	/* Patch point for checking crashes */
802 #if defined( __WINDOWS__ ) && 1
803 	{
804 	char buffer[ 128 ];
805 
806 	for( i = 0/*0*/; i < 200; i++ )
807 		{
808 		FILE *filePtr;
809 
810 		sprintf( buffer, "r:/%s/%06d.dat", cmd, i );
811 		filePtr = fopen( buffer, "rb" );
812 		if( filePtr == NULL )
813 			{
814 			puts( "No more files, exiting." );
815 			break;
816 			}
817 		fclose( filePtr );
818 		printf( "Fuzzing %s file %d (%s).\n", cmd, i, buffer );
819 		if( fuzzType >= 1000 && fuzzType <= 1100 )
820 			status = fuzzFile( buffer );
821 		else
822 		if( fuzzType >= 2000 && fuzzType <= 2100 )
823 			status = fuzzEnvelope( buffer );
824 		else
825 		if( fuzzType >= 3000 && fuzzType <= 3100 )
826 			status = fuzzKeyset( buffer );
827 		else
828 		if( fuzzType >= 4000 && fuzzType <= 4100 )
829 			status = fuzzSpecial( fuzzType, buffer );
830 		else
831 			status = fuzzSession( fuzzType, buffer );
832 		}
833 	puts( "Done." );
834 	if( i <= 0 )
835 		{
836 		puts( "Warning: No input files processed." );
837 		getchar();
838 		}
839 	}
840 #endif /* __WINDOWS__ test */
841 
842 	/* Fuzz the target file */
843 	if( fuzzType >= 1000 && fuzzType <= 1100 )
844 		status = fuzzFile( arg );
845 	else
846 	if( fuzzType >= 2000 && fuzzType <= 2100 )
847 		status = fuzzEnvelope( arg );
848 	else
849 	if( fuzzType >= 3000 && fuzzType <= 3100 )
850 		status = fuzzKeyset( arg );
851 	else
852 	if( fuzzType >= 4000 && fuzzType <= 4100 )
853 		status = fuzzSpecial( fuzzType, arg );
854 	else
855 	if( fuzzType > CRYPT_SESSION_NONE && fuzzType < CRYPT_SESSION_LAST )
856 		status = fuzzSession( fuzzType, arg );
857 	else
858 		{
859 		printf( "Error: Unknown fuzz type '%d'.\n", fuzzType );
860 		exit( EXIT_FAILURE );
861 		}
862 	if( cryptStatusError( status ) )
863 		{
864 		/* The fuzz init failed, make sure that the wrapper records this */
865 		exit( EXIT_FAILURE );
866 		}
867 
868 	exit( EXIT_SUCCESS );
869 	}
870 #endif /* CONFIG_FUZZ && debug mode */
871 
872 /****************************************************************************
873 *																			*
874 *								Misc.Kludges								*
875 *																			*
876 ****************************************************************************/
877 
878 /* Generic test code insertion point.  The following routine is called
879    before any of the other tests are run and can be used to handle special-
880    case tests that aren't part of the main test suite */
881 
882 void initDatabaseKeysets( void );	/* Call before calling cert-mgt.code */
883 
testKludge(const char * cmd,const char * arg)884 static void testKludge( const char *cmd, const char *arg )
885 	{
886 	/* Fuzzing test harness.  This is a noreturn function */
887 #ifdef CONFIG_FUZZ
888 	fuzz( cmd, arg );
889 #endif /* CONFIG_FUZZ */
890 
891 	/* Performance-testing test harness */
892 #if 0
893 	void performanceTests( const CRYPT_DEVICE cryptDevice );
894 
895 	performanceTests( CRYPT_UNUSED );
896 #endif /* 0 */
897 
898 	/* Simple (brute-force) server code. NB: Remember to change
899 	   setLocalConnect() to not bind the server to localhost if expecting
900 	   external connections */
901 #if 0
902 	while( TRUE )
903 		testSessionTSPServer();
904 #endif /* 0 */
905 
906 	/* Exit point for the test harnesses above, used when we don't want to
907 	   fall through to the main test code */
908 #if 0
909 	cleanupAndExit( EXIT_SUCCESS );
910 #endif /* 0 */
911 	}
912 
913 /****************************************************************************
914 *																			*
915 *								Main Test Code								*
916 *																			*
917 ****************************************************************************/
918 
919 /* Comprehensive cryptlib functionality test.  To get the following to run
920    under WinCE as a native console app it's necessary to change the entry
921    point in Settings | Link | Output from WinMainCRTStartup to the
922    undocumented mainACRTStartup, which calls main() rather than WinMain(),
923    however this only works if the system has a native console-mode driver
924    (most don't) */
925 
main(int argc,char ** argv)926 int main( int argc, char **argv )
927 	{
928 	const char *zCmdPtr = NULL, *zArgPtr = NULL;
929 	BOOLEAN sessionTestError = FALSE, loopbackTestError = FALSE;
930 	int flags, status;
931 	void testSystemSpecific1( void );
932 	void testSystemSpecific2( void );
933 
934 	/* If we're running in test mode, run the test code and exit */
935 #ifdef CONFIG_SUITEB_TESTS
936 	return( suiteBMain( argc, argv ) );
937 #endif /* CONFIG_SUITEB_TESTS */
938 
939 	/* Print a general banner to let the user know what's going on */
940 	printf( "testlib - cryptlib %d-bit self-test framework.\n",
941 			( int ) sizeof( long ) * 8 );	/* Cast for gcc */
942 	puts( "Copyright Peter Gutmann 1995 - 2015." );
943 #ifdef CONFIG_FUZZ
944 	puts( "" );
945 	puts( "Warning: This is a custom fuzz-test build that operates in a nonstandard manner." );
946 	puts( "         Not to be used in a standard test or production environment." );
947 #endif /* CONFIG_FUZZ */
948 	puts( "" );
949 
950 	/* Skip the program name and process any command-line arguments */
951 	argv++; argc--;
952 	status = processArgs( argc, argv, &flags, &zCmdPtr, &zArgPtr );
953 	if( !status )
954 		exit( EXIT_FAILURE );
955 
956 #ifdef USE_TCHECK
957 	THREAD_DEBUG_SUSPEND();
958 #endif /* USE_TCHECK */
959 
960 	/* Make sure that various system-specific features are set right */
961 	testSystemSpecific1();
962 
963 	/* VisualAge C++ doesn't set the TZ correctly.  The check for this isn't
964 	   as simple as it would seem since most IBM compilers define the same
965 	   preprocessor values even though it's not documented anywhere, so we
966 	   have to enable the tzset() call for (effectively) all IBM compilers
967 	   and then disable it for ones other than VisualAge C++ */
968 #if ( defined( __IBMC__ ) || defined( __IBMCPP__ ) ) && !defined( __VMCMS__ )
969 	tzset();
970 #endif /* VisualAge C++ */
971 
972 	/* Set up the output stream to which diagnostic output is sent */
973 	outputStream = stdout;
974 
975 	/* Perform memory-allocation fault injection.  We have to do this before
976 	   we call cryptInit() since the init code itself is tested by the
977 	   memory fault-injection */
978 #ifdef TEST_MEMFAULT
979 	testMemFault();
980 #endif /* TEST_MEMFAULT */
981 
982 	/* Initialise cryptlib */
983 	printf( "Initialising cryptlib..." );
984 	status = cryptInit();
985 	if( cryptStatusError( status ) )
986 		{
987 		printf( "\ncryptInit() failed with error code %d, line %d.\n",
988 				status, __LINE__ );
989 		exit( EXIT_FAILURE );
990 		}
991 	puts( "done." );
992 
993 	/* In order to avoid having to do a randomness poll for every test run,
994 	   we bypass the randomness-handling by adding some junk.  This is only
995 	   enabled when cryptlib is built in debug mode so it won't work with
996 	   any production systems */
997 #ifndef TEST_RANDOM
998   #if defined( __MVS__ ) || defined( __VMCMS__ )
999 	#pragma convlit( resume )
1000 	cryptAddRandom( "xyzzy", 5 );
1001 	#pragma convlit( suspend )
1002   #else
1003 	cryptAddRandom( "xyzzy", 5 );
1004   #endif /* Special-case EBCDIC handling */
1005 #endif /* TEST_RANDOM */
1006 
1007 	/* Perform a general sanity check to make sure that the self-test is
1008 	   being run the right way */
1009 #ifndef CONFIG_FUZZ
1010 	if( !checkFileAccess() )
1011 		{
1012 		cryptEnd();
1013 		exit( EXIT_FAILURE );
1014 		}
1015 #endif /* CONFIG_FUZZ */
1016 
1017 	/* Make sure that further system-specific features that require cryptlib
1018 	   to be initialised to check are set right */
1019 #ifndef _WIN32_WCE
1020 	testSystemSpecific2();
1021 #endif /* WinCE */
1022 
1023 #ifdef USE_TCHECK
1024 	THREAD_DEBUG_RESUME();
1025 #endif /* USE_TCHECK */
1026 
1027 	/* For general testing purposes we can insert test code at this point to
1028 	   test special cases that aren't covered in the general tests below */
1029 	testKludge( zCmdPtr, zArgPtr );
1030 
1031 #ifdef SMOKE_TEST
1032 	/* Perform a general smoke test of the kernel */
1033 	smokeTest();
1034 #endif /* SMOKE_TEST */
1035 
1036 	/* Test each block of cryptlib functionality */
1037 	if( ( flags & DO_SELFTEST ) && !testSelfTest() )
1038 		goto errorExit;
1039 	if( ( flags & DO_LOWLEVEL ) && !testLowLevel() )
1040 		goto errorExit;
1041 	if( ( flags & DO_RANDOM ) && !testRandom() )
1042 		goto errorExit;
1043 	if( ( flags & DO_CONFIG ) && !testConfig() )
1044 		goto errorExit;
1045 	if( ( flags & DO_DEVICE ) && !testDevice() )
1046 		goto errorExit;
1047 	if( ( flags & DO_MIDLEVEL ) && !testMidLevel() )
1048 		goto errorExit;
1049 	if( ( flags & DO_CERT ) && !testCert() )
1050 		goto errorExit;
1051 	if( ( flags & DO_KEYSETFILE ) && !testKeysetFile() )
1052 		goto errorExit;
1053 	if( ( flags & DO_KEYSETDBX ) && !testKeysetDatabase() )
1054 		goto errorExit;
1055 	if( ( flags & DO_CERTPROCESS ) && !testCertMgmt() )
1056 		goto errorExit;
1057 	if( ( flags & DO_HIGHLEVEL ) && !testHighLevel() )
1058 		goto errorExit;
1059 	if( ( flags & DO_ENVELOPE ) && !testEnveloping() )
1060 		goto errorExit;
1061 	if( ( flags & DO_SESSION ) && !testSessions() )
1062 		{
1063 		sessionTestError = TRUE;
1064 		goto errorExit;
1065 		}
1066 	if( ( flags & DO_SESSIONLOOPBACK ) && !testSessionsLoopback() )
1067 		{
1068 		loopbackTestError = TRUE;
1069 		goto errorExit;
1070 		}
1071 	if( ( flags & DO_USER  ) && !testUsers() )
1072 		goto errorExit;
1073 
1074 	/* Shut down cryptlib */
1075 	status = cryptEnd();
1076 	if( cryptStatusError( status ) )
1077 		{
1078 		if( status == CRYPT_ERROR_INCOMPLETE )
1079 			{
1080 			puts( "cryptEnd() failed with error code CRYPT_ERROR_INCOMPLETE, "
1081 				  "a code path in the\nself-test code resulted in an error "
1082 				  "return without a full cleanup of objects.\nIf you were "
1083 				  "running the multithreaded loopback tests this may be "
1084 				  "because one\nor more threads lost sync with other threads "
1085 				  "and exited without cleaning up\nits objects.  This "
1086 				  "happens occasionally due to network timing issues or\n"
1087 				  "thread scheduling differences." );
1088 			}
1089 		else
1090 			{
1091 			printf( "cryptEnd() failed with error code %d, line %d.\n",
1092 					status, __LINE__ );
1093 			}
1094 		goto errorExit1;
1095 		}
1096 
1097 	puts( "All tests concluded successfully." );
1098 	return( EXIT_SUCCESS );
1099 
1100 	/* All errors end up here */
1101 errorExit:
1102 	cryptEnd();
1103 errorExit1:
1104 	puts( "\nThe test was aborted due to an error being detected.  If you "
1105 		  "want to report\nthis problem, please provide as much information "
1106 		  "as possible to allow it to\nbe diagnosed, for example the call "
1107 		  "stack, the location inside cryptlib where\nthe problem occurred, "
1108 		  "and the values of any variables that might be\nrelevant." );
1109 	if( sessionTestError )
1110 		{
1111 		puts( "\nThe error occurred during one of the network session tests, "
1112 			  "if the error\nmessage indicates a network-level problem such "
1113 			  "as ECONNREFUSED, ECONNRESET,\nor a timeout or read error then "
1114 			  "this is either due to a transient\nnetworking problem or a "
1115 			  "firewall interfering with network connections.  This\nisn't a "
1116 			  "cryptlib error, and doesn't need to be reported." );
1117 		}
1118 	if( loopbackTestError )
1119 		{
1120 		puts( "\nThe error occurred during one of the multi-threaded network "
1121 			  "loopback\ntests, this was probably due to the different threads "
1122 			  "losing synchronisation.\nFor the secure sessions this usually "
1123 			  "results in read/write, timeout, or\nconnection-closed errors "
1124 			  "when one thread is pre-empted for too long.  For the\n"
1125 			  "certificate-management sessions it usually results in an error "
1126 			  "related to the\nserver being pre-empted for too long by database "
1127 			  "updates.  Since the self-\ntest exists only to exercise "
1128 			  "cryptlib's capabilities, it doesn't bother with\ncomplex thread "
1129 			  "synchronisation during the multi-threaded loopback tests.\nThis "
1130 			  "type of error is non-fatal, and should disappear if the test is "
1131 			  "re-run." );
1132 		}
1133 
1134 	cleanExit( EXIT_FAILURE );
1135 	return( EXIT_FAILURE );		/* Exists only to get rid of compiler warnings */
1136 	}
1137 
1138 /* PalmOS wrapper for main() */
1139 
1140 #ifdef __PALMSOURCE__
1141 
1142 #include <CmnErrors.h>
1143 #include <CmnLaunchCodes.h>
1144 
PilotMain(uint16_t cmd,void * cmdPBP,uint16_t launchFlags)1145 uint32_t PilotMain( uint16_t cmd, void *cmdPBP, uint16_t launchFlags )
1146 	{
1147 	switch( cmd )
1148 		{
1149 		case sysAppLaunchCmdNormalLaunch:
1150 			main( 0, NULL );
1151 		}
1152 
1153 	return( errNone );
1154 	}
1155 #endif /* __PALMSOURCE__ */
1156 
1157 /* Symbian wrapper for main() */
1158 
1159 #ifdef __SYMBIAN__
1160 
E32Main(void)1161 GLDEF_C TInt E32Main( void )
1162 	{
1163 	main( 0, NULL );
1164 
1165 	return( KErrNone );
1166 	}
1167 
1168 #ifdef __WINS__
1169 
1170 /* Support functions for use under the Windows emulator */
1171 
WinsMain(void)1172 EXPORT_C TInt WinsMain( void )
1173 	{
1174 	E32Main();
1175 
1176 	return( KErrNone );
1177 	}
1178 
E32Dll(TDllReason)1179 TInt E32Dll( TDllReason )
1180 	{
1181 	/* Entry point for the DLL loader */
1182 	return( KErrNone );
1183 	}
1184 #endif /* __WINS__ */
1185 
1186 #endif /* __SYMBIAN__ */
1187 
1188 /* Test the system-specific defines in crypt.h.  This is the last function in
1189    the file because we want to avoid any definitions in crypt.h messing with
1190    the rest of the test.c code.
1191 
1192    The following include is needed only so we can check whether the defines
1193    are set right.  crypt.h should never be included in a program that uses
1194    cryptlib */
1195 
1196 #undef __WINDOWS__
1197 #undef __WIN16__
1198 #undef __WIN32__
1199 #undef BOOLEAN
1200 #undef BYTE
1201 #undef FALSE
1202 #undef TRUE
1203 #undef FAR_BSS
1204 #define IN_STRING		/* No-op out define normally in analyse.h */
1205 #ifdef HIRES_FORMAT_SPECIFIER
1206   #undef HIRES_FORMAT_SPECIFIER
1207   #define HIRES_TIME	HIRES_TIME_ALT	/* Rename typedef'd value */
1208 #endif /* HIRES_TIME */
1209 #if defined( __MVS__ ) || defined( __VMCMS__ )
1210   #pragma convlit( resume )
1211 #endif /* Resume ASCII use on EBCDIC systems */
1212 #if defined( __ILEC400__ )
1213   #pragma convert( 819 )
1214 #endif /* Resume ASCII use on EBCDIC systems */
1215 #ifdef _MSC_VER
1216   #include "../crypt.h"
1217 #else
1218   #include "crypt.h"
1219 #endif /* Braindamaged MSC include handling */
1220 #if defined( __MVS__ ) || defined( __VMCMS__ )
1221   #pragma convlit( suspend )
1222 #endif /* Suspend ASCII use on EBCDIC systems */
1223 #if defined( __ILEC400__ )
1224   #pragma convert( 0 )
1225 #endif /* Suspend ASCII use on EBCDIC systems */
1226 #undef mktime		/* Undo mktime() bugfix in crypt.h */
1227 
1228 #ifndef _WIN32_WCE
1229 
testTime(const int year)1230 static time_t testTime( const int year )
1231 	{
1232 	struct tm theTime;
1233 
1234 	memset( &theTime, 0, sizeof( struct tm ) );
1235 	theTime.tm_isdst = -1;
1236 	theTime.tm_year = 100 + year;
1237 	theTime.tm_mon = 5;
1238 	theTime.tm_mday = 5;
1239 	theTime.tm_hour = 12;
1240 	theTime.tm_min = 13;
1241 	theTime.tm_sec = 14;
1242 	return( mktime( &theTime ) );
1243 	}
1244 #endif /* !WinCE */
1245 
testSystemSpecific1(void)1246 void testSystemSpecific1( void )
1247 	{
1248 #if 0	/* See comment below */
1249 	const CRYPT_ATTRIBUTE_TYPE testType = -1;
1250 #endif /* 0 */
1251 	struct {
1252 		/* We have to make sure that the following char string is longword-
1253 		   aligned since we're about to cast it to a long and dereference
1254 		   it */
1255 		const void *alignDummy;
1256 		const char endiannessCheck[ 10 ];
1257 		}
1258 	endiannessCheckValue = { NULL, "\x80\x00\x00\x00\x00\x00\x00\x00" };
1259 	int bigEndian;
1260 #ifndef _WIN32_WCE
1261 	int i;
1262 #endif /* WinCE */
1263 
1264 	/* Make sure that we've got the endianness set right.  If the machine is
1265 	   big-endian (up to 64 bits) the following value will be signed,
1266 	   otherwise it will be unsigned.  We can't easily test for things like
1267 	   middle-endianness without knowing the size of the data types, but
1268 	   then again it's unlikely we're being run on a PDP-11 */
1269 	bigEndian = ( *( long * ) endiannessCheckValue.endiannessCheck < 0 );
1270 #ifdef DATA_LITTLEENDIAN
1271 	if( bigEndian )
1272 		{
1273 		puts( "The CPU endianness define is set wrong in crypt.h, this "
1274 			  "machine appears to be\nbig-endian, not little-endian.  Edit "
1275 			  "the file and rebuild cryptlib." );
1276 		exit( EXIT_FAILURE );
1277 		}
1278 #else
1279 	if( !bigEndian )
1280 		{
1281 		puts( "The CPU endianness define is set wrong in crypt.h, this "
1282 			  "machine appears to be\nlittle-endian, not big-endian.  Edit "
1283 			  "the file and rebuild cryptlib." );
1284 		exit( EXIT_FAILURE );
1285 		}
1286 #endif /* DATA_LITTLEENDIAN */
1287 
1288 	/* Make sure that the compiler doesn't use variable-size enums (done by,
1289 	   for example, the PalmOS SDK for backwards compatibility with
1290 	   architectural decisions made for 68K-based PalmPilots) */
1291 	if( sizeof( CRYPT_ALGO_TYPE ) != sizeof( int ) || \
1292 		sizeof( CRYPT_MODE_TYPE ) != sizeof( int ) ||
1293 		sizeof( CRYPT_ATTRIBUTE_TYPE ) != sizeof( int ) )
1294 		{
1295 		puts( "The compiler you are using treats enumerated types as "
1296 			  "variable-length non-\ninteger values, making it impossible "
1297 			  "to reliably pass the address of an\nenum as a function "
1298 			  "parameter.  To fix this you need to rebuild cryptlib\nwith "
1299 			  "the appropriate compiler option or pragma to ensure that\n"
1300 			  "sizeof( enum ) == sizeof( int )." );
1301 		exit( EXIT_FAILURE );
1302 		}
1303 
1304 #if 0	/* The ANSI C default is 'int' with signedness being unimportant,
1305 		   MSVC defaults to signed, gcc defaults to unsigned, and cryptlib
1306 		   works with either, so whatever the CodeSourcery build of gcc is
1307 		   doing it's more serious than a simple signedness issue */
1308 	/* Make sure that the compiler doesn't use unsigned enums (for example a
1309 	   mutant CodeSourcery build of gcc for eCos does this) */
1310 	if( testType >= 0 )
1311 		{
1312 		puts( "The compiler you are using treats enumerated types as "
1313 			  "unsigned values,\nmaking it impossible to reliably use enums "
1314 			  "in conjunction with standard\n(signed) integers.  To fix this "
1315 			  "you need to rebuild cryptlib with the\nappropriate compiler "
1316 			  "option or pragma to ensure that enumerated types\nare signed "
1317 			  "like standard data types." );
1318 		exit( EXIT_FAILURE );
1319 		}
1320 #endif /* 0 */
1321 
1322 	/* Make sure that mktime() works properly (there are some systems on
1323 	   which it fails well before 2038) */
1324 #ifndef _WIN32_WCE
1325 	for( i = 10; i < 36; i ++ )
1326 		{
1327 		const time_t theTime = testTime( i );
1328 
1329 		if( theTime < 0 )
1330 			{
1331 			printf( "Warning: This system has a buggy mktime() that can't "
1332 					"handle dates beyond %d.\n         Some certificate tests "
1333 					"will fail, and long-lived CA certificates\n         won't "
1334 					"be correctly imported.\nPress a key...\n", 2000 + i );
1335 			getchar();
1336 			break;
1337 			}
1338 		}
1339 #endif /* !WinCE */
1340 
1341 	/* If we're compiling under Unix with threading support, make sure the
1342 	   default thread stack size is sensible.  We don't perform the check for
1343 	   UnixWare/SCO since this already has the workaround applied */
1344 #if defined( UNIX_THREADS ) && !defined( __SCO_VERSION__ )
1345 	{
1346 	pthread_attr_t attr;
1347 	size_t stackSize;
1348 
1349 	pthread_attr_init( &attr );
1350 	pthread_attr_getstacksize( &attr, &stackSize );
1351     pthread_attr_destroy( &attr );
1352   #if ( defined( sun ) && OSVERSION > 4 )
1353 	/* Slowaris uses a special-case value of 0 (actually NULL) to indicate
1354 	   the default stack size of 1MB (32-bit) or 2MB (64-bit), so we have to
1355 	   handle this specially */
1356 	if( stackSize < 32768 && stackSize != 0 )
1357   #else
1358 	if( stackSize < 32768 )
1359   #endif /* Slowaris special-case handling */
1360 		{
1361 		printf( "The pthread stack size is defaulting to %ld bytes, which is "
1362 				"too small for\ncryptlib to run in.  To fix this, edit the "
1363 				"thread-creation function macro in\ncryptos.h and recompile "
1364 				"cryptlib.\n", ( long ) stackSize );
1365 		exit( EXIT_FAILURE );
1366 		}
1367 	}
1368 #endif /* UNIX_THREADS */
1369 	}
1370 
1371 #ifndef _WIN32_WCE	/* Windows CE doesn't support ANSI C time functions */
1372 
testSystemSpecific2(void)1373 void testSystemSpecific2( void )
1374 	{
1375 	CRYPT_CERTIFICATE cryptCert;
1376 	const time_t theTime = time( NULL ) - 5;
1377 	int status;
1378 
1379 	/* Make sure that the cryptlib and non-cryptlib code use the same time_t
1380 	   size (some systems are moving from 32- to 64-bit time_t, which can
1381 	   lead to problems if the library and calling code are built with
1382 	   different sizes) */
1383 	status = cryptCreateCert( &cryptCert, CRYPT_UNUSED,
1384 							  CRYPT_CERTTYPE_CERTIFICATE );
1385 	if( cryptStatusError( status ) )
1386 		{
1387 		if( status == CRYPT_ERROR_NOTAVAIL )
1388 			{
1389 			puts( "Couldn't create certificate object for time sanity-check "
1390 				  "because certificate\n" "use has been disabled, skipping "
1391 				  "time sanity check...\n" );
1392 			return;
1393 			}
1394 		puts( "Couldn't create certificate object for time sanity-check." );
1395 		exit( EXIT_FAILURE );
1396 		}
1397 	status = cryptSetAttributeString( cryptCert, CRYPT_CERTINFO_VALIDFROM,
1398 									  &theTime, sizeof( time_t ) );
1399 	cryptDestroyCert( cryptCert );
1400 	if( status == CRYPT_ERROR_PARAM4 )
1401 		{
1402 		printf( "Warning: This compiler is using a %ld-bit time_t data type, "
1403 				"which appears to be\n         different to the one that "
1404 				"was used when cryptlib was built.  This\n         situation "
1405 				"usually occurs when the compiler allows the use of both\n"
1406 				"         32- and 64-bit time_t data types and different "
1407 				"options were\n         selected for building cryptlib and "
1408 				"the test app.  To resolve this,\n         ensure that both "
1409 				"cryptlib and the code that calls it use the same\n"
1410 				"         time_t data type.\n",
1411 				( long ) sizeof( time_t ) * 8 );
1412 		exit( EXIT_FAILURE );
1413 		}
1414 	}
1415 #endif /* WinCE */
1416