cryptlib  3.4.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros
testlib.c
Go to the documentation of this file.
1 /****************************************************************************
2 * *
3 * cryptlib Test Code *
4 * Copyright Peter Gutmann 1995-2011 *
5 * *
6 ****************************************************************************/
7 
8 #include <ctype.h> /* For toupper() */
9 
10 #include "cryptlib.h"
11 #include "test/test.h"
12 
13 #if defined( __MVS__ ) || defined( __VMCMS__ )
14  /* Suspend conversion of literals to ASCII. */
15  #pragma convlit( suspend )
16 #endif /* IBM big iron */
17 #if defined( __ILEC400__ )
18  #pragma convert( 0 )
19 #endif /* IBM medium iron */
20 
21 /* Optionally include and activate the Visual Leak Detector library if
22  we're running a debug build under VC++ 6.0. Note that this can't be
23  run at the same time as Bounds Checker, since the two interefere with
24  each other */
25 
26 #if defined( _MSC_VER ) && ( _MSC_VER == 1200 ) && 0
27  #include "binaries/vld.h"
28 #endif /* VC++ 6.0 */
29 
30 /* Optionally include the Intel Thread Checker API to control analysis */
31 
32 #if defined( _MSC_VER ) && ( _MSC_VER == 1200 ) && 0
33  #define USE_TCHECK
34  #include "../../../Intel/VTune/tcheck/Include/libittnotify.h"
35  #include "../../../Intel/VTune/Analyzer/Include/VtuneApi.h"
36  #pragma comment( lib, "C:/Program Files/Intel/VTune/Analyzer/Lib/libittnotify.lib" )
37  #pragma comment( lib, "C:/Program Files/Intel/VTune/Analyzer/Lib/VtuneApi.lib " )
38  #define THREAD_DEBUG_SUSPEND() __itt_pause(); VTPause()
39  #define THREAD_DEBUG_RESUME() VTResume(); __itt_resume()
40 #else
41  #define THREAD_DEBUG_SUSPEND()
42  #define THREAD_DEBUG_RESUME()
43 #endif /* VC++ 6.0 with Intel Thread Checker */
44 
45 /* Warn about nonstandard build options */
46 
47 #if defined( CONFIG_SUITEB_TESTS ) && defined( _MSC_VER )
48  #pragma message( " Building Suite B command-line test configuration." )
49 #endif /* CONFIG_SUITEB_TESTS with VC++ */
50 
51 /* Whether various keyset tests worked, the results are used later to test
52  other routines. We initially set the key read result to TRUE in case the
53  keyset read tests are never called, so we can still trying reading the
54  keys in other tests */
55 
57 
58 /* There are some sizeable (for DOS) data structures used, so we increase the
59  stack size to allow for them */
60 
61 #if defined( __MSDOS16__ ) && defined( __TURBOC__ )
62  extern unsigned _stklen = 16384;
63 #endif /* __MSDOS16__ && __TURBOC__ */
64 
65 /* Prototypes for general debug routines used to evaluate problems with certs
66  and envelopes from other apps */
67 
68 void xxxCertImport( const char *fileName );
69 void xxxCertCheck( const char *certFileName, const char *caFileNameOpt );
70 void xxxPubKeyRead( const char *fileName, const char *keyName );
71 void xxxPrivKeyRead( const char *fileName, const char *keyName, const char *password );
72 void xxxDataImport( const char *fileName );
73 void xxxSignedDataImport( const char *fileName );
74 void xxxEncryptedDataImport( const char *fileName );
75 
76 /* Prototype for custom key-creation routines */
77 
78 int createTestKeys( void );
79 
80 /* Prototype for stress test interface routine */
81 
82 void smokeTest( void );
83 
84 /* Prototype for Suite B test entry point */
85 
86 #if defined( CONFIG_SUITEB_TESTS )
87 
88 int suiteBMain( int argc, char **argv );
89 
90 #endif /* CONFIG_SUITEB_TESTS */
91 
92 /****************************************************************************
93 * *
94 * Utility Routines *
95 * *
96 ****************************************************************************/
97 
98 /* Update the cryptlib config file. This code can be used to set the
99  information required to load PKCS #11 device drivers:
100 
101  - Set the driver path in the CRYPT_OPTION_DEVICE_PKCS11_DVR01 setting
102  below.
103  - Add a call to updateConfig() from somewhere (e.g.the test kludge function).
104  - Run the test code until it calls updateConfig().
105  - Remove the updateConfig() call, then run the test code as normal.
106  The testDevices() call will report the results of trying to use your
107  driver.
108 
109  Note that under Windows XP the path name changes from 'WinNT' to just
110  'Windows' */
111 
112 static void updateConfig( void )
113  {
114 #if 0
115  const char *driverPath = "c:/winnt/system32/acospkcs11.dll";/* ACOS */
116  const char *driverPath = "c:/winnt/system32/aetpkss1.dll"; /* AET */
117  const char *driverPath = "c:/winnt/system32/aloaha_pkcs11.dll"; /* Aloaha */
118  const char *driverPath = "c:/winnt/system32/etpkcs11.dll"; /* Aladdin eToken */
119  const char *driverPath = "c:/winnt/system32/psepkcs11.dll"; /* A-Sign */
120  const char *driverPath = "c:/winnt/system32/asepkcs.dll"; /* Athena */
121  const char *driverPath = "c:/winnt/system32/cryst32.dll"; /* Chrysalis */
122  const char *driverPath = "c:/program files/luna/cryst201.dll"; /* Chrysalis */
123  const char *driverPath = "c:/winnt/system32/pkcs201n.dll"; /* Datakey */
124  const char *driverPath = "c:/winnt/system32/dkck201.dll"; /* Datakey (for Entrust) */
125  const char *driverPath = "c:/winnt/system32/dkck232.dll"; /* Datakey/iKey (NB: buggy, use 201) */
126  const char *driverPath = "c:/program files/eracom/cprov sw/cryptoki.dll"; /* Eracom (old, OK) */
127  const char *driverPath = "c:/program files/eracom/cprov runtime/cryptoki.dll"; /* Eracom (new, doesn't work) */
128  const char *driverPath = "c:/winnt/system32/sadaptor.dll"; /* Eutron */
129  const char *driverPath = "c:/winnt/system32/ngp11v211.dll"; /* Feitain Technology */
130  const char *driverPath = "c:/winnt/system32/pk2priv.dll"; /* Gemplus */
131  const char *driverPath = "c:/program files/gemplus/gclib.dll"; /* Gemplus */
132  const char *driverPath = "c:/winnt/system32/cryptoki.dll"; /* IBM */
133  const char *driverPath = "c:/winnt/system32/csspkcs11.dll"; /* IBM */
134  const char *driverPath = "c:/winnt/system32/ibmpkcss.dll"; /* IBM */
135  const char *driverPath = "c:/winnt/system32/id2cbox.dll"; /* ID2 */
136  const char *driverPath = "c:/winnt/system32/cknfast.dll"; /* nCipher */
137  const char *driverPath = "/opt/nfast/toolkits/pkcs11/libcknfast.so";/* nCipher under Unix */
138  const char *driverPath = "/usr/lib/libcknfast.so"; /* nCipher under Unix */
139  const char *driverPath = "softokn3.dll"; /* Netscape */
140  const char *driverPath = "c:/winnt/system32/nxpkcs11.dll"; /* Nexus */
141  const char *driverPath = "c:/winnt/system32/AuCryptoki2-0.dll"; /* Oberthur */
142  const char *driverPath = "c:/winnt/system32/opensc-pkcs11.dll"; /* OpenSC */
143  const char *driverPath = "c:/winnt/system32/micardoPKCS11.dll"; /* Orga Micardo */
144  const char *driverPath = "c:/winnt/system32/cryptoki22.dll";/* Rainbow HSM (for USB use Datakey dvr) */
145  const char *driverPath = "c:/winnt/system32/p11card.dll"; /* Safelayer HSM (for USB use Datakey dvr) */
146  const char *driverPath = "c:/winnt/system32/slbck.dll"; /* Schlumberger */
147  const char *driverPath = "c:/winnt/system32/SetTokI.dll"; /* SeTec */
148  const char *driverPath = "c:/winnt/system32/siecap11.dll"; /* Siemens */
149  const char *driverPath = "c:/winnt/system32/smartp11.dll"; /* SmartTrust */
150  const char *driverPath = "c:/winnt/system32/SpyPK11.dll"; /* Spyrus */
151 #endif /* 0 */
152  const char *driverPath = "c:/program files/eracom/cprov sw/cryptoki.dll"; /* Eracom (old, OK) */
153  int status;
154 
155  printf( "Updating cryptlib configuration to load PKCS #11 driver\n "
156  "'%s'\n as default driver...", driverPath );
157 
158  /* Set the path for a PKCS #11 device driver. We only enable one of
159  these at a time to speed the startup time */
162  driverPath, strlen( driverPath ) );
163  if( cryptStatusError( status ) )
164  {
165  printf( "\n\nError updating PKCS #11 device driver profile, "
166  "status %d.\n", status );
167  return;
168  }
169 
170  /* Flush the updated options to disk */
172  if( cryptStatusError( status ) )
173  {
174  printf( "\n\nError comitting device driver profile update to disk, "
175  "status %d.\n", status );
176  return;
177  }
178 
179  puts( " done.\n\nYou'll need to restart cryptlib for the changes to "
180  "take effect." );
181  cryptEnd();
182  puts( "\nPress a key to exit." );
183  getchar();
184  exit( EXIT_SUCCESS );
185  }
186 
187 /* Add trusted certs to the config file and make sure that they're
188  persistent. This can't be done in the normal self-test since it requires
189  that cryptlib be restarted as part of the test to re-read the config file,
190  and because it modifies the cryptlib config file */
191 
192 static void updateConfigCert( void )
193  {
194  CRYPT_CERTIFICATE trustedCert;
195  int status;
196 
197  /* Import the first certificate, make it trusted, and commit the changes */
198  importCertFromTemplate( &trustedCert, CERT_FILE_TEMPLATE, 1 );
201  cryptDestroyCert( trustedCert );
202  cryptEnd();
203 
204  /* Do the same with a second certificate. At the conclusion of this, we
205  should have two trusted certificates on disk */
206  status = cryptInit();
207  if( cryptStatusError( status ) )
208  {
209  puts( "Couldn't reload cryptlib configuration." );
210  return;
211  }
212  importCertFromTemplate( &trustedCert, CERT_FILE_TEMPLATE, 2 );
215  cryptDestroyCert( trustedCert );
216  cryptEnd();
217  }
218 
219 /****************************************************************************
220 * *
221 * Argument Processing *
222 * *
223 ****************************************************************************/
224 
225 /* Flags for the tests that we want to perform */
226 
227 #define DO_SELFTEST 0x0001
228 #define DO_LOWLEVEL 0x0002
229 #define DO_RANDOM 0x0004
230 #define DO_CONFIG 0x0008
231 #define DO_DEVICE 0x0010
232 #define DO_MIDLEVEL 0x0020
233 #define DO_CERT 0x0040
234 #define DO_KEYSETFILE 0x0080
235 #define DO_KEYSETDBX 0x0100
236 #define DO_CERTPROCESS 0x0200
237 #define DO_HIGHLEVEL 0x0400
238 #define DO_ENVELOPE 0x0800
239 #define DO_SESSION 0x1000
240 #define DO_SESSIONLOOPBACK 0x2000
241 #define DO_USER 0x4000
242 
243 #define DO_ALL 0xFFFF
244 
245 /* Show usage and exit */
246 
247 static void usageExit( void )
248  {
249  puts( "Usage: testlib [-bcdefhiklmoprstu]" );
250 
251  puts( " Encryption function tests:" );
252  puts( " -l = Test low-level functions" );
253  puts( " -m = Test mid-level functions" );
254  puts( " -i = Test high-level functions" );
255  puts( "" );
256 
257  puts( " Subsystem tests:" );
258  puts( " -c = Test certificate subsystem" );
259  puts( " -d = Test device subsystem" );
260  puts( " -f = Test file keyset subsystem" );
261  puts( " -k = Test database keyset subsystem" );
262  puts( " -e = Test envelope subsystem" );
263  puts( " -s = Test session subsystem" );
264  puts( " -t = Test session subsystem via loopback interface" );
265  puts( " -u = Test user subsystem" );
266  puts( "" );
267 
268  puts( " Miscellaneous tests:" );
269  puts( " -r = Test entropy-gathering routines" );
270  puts( " -b = Perform built-in self-test" );
271  puts( " -o = Test configuration management routines" );
272  puts( " -p = Test certificate processing" );
273  puts( "" );
274 
275  puts( " Other options:" );
276  puts( " -h = Display this help text" );
277  puts( " -- = End of arg list" );
278  puts( "" );
279 
280  puts( "Default is to test all cryptlib subsystems." );
281  exit( EXIT_FAILURE );
282  }
283 
284 /* Process command-line arguments */
285 
286 static int processArgs( int argc, char **argv,
287  int *argFlags, const char **zargPtrPtr )
288  {
289  const char *zargPtr = NULL;
290  BOOLEAN moreArgs = TRUE;
291 
292  /* Clear return value */
293  *argFlags = 0;
294  *zargPtrPtr = NULL;
295 
296  /* No args means test everything */
297  if( argc <= 0 )
298  {
299  *argFlags = DO_ALL;
300 
301  return( TRUE );
302  }
303 
304  /* Check for arguments */
305  while( argc > 0 && *argv[ 0 ] == '-' && moreArgs )
306  {
307  const char *argPtr = argv[ 0 ] + 1;
308 
309  while( *argPtr )
310  {
311  switch( toupper( *argPtr ) )
312  {
313  case '-':
314  moreArgs = FALSE; /* GNU-style end-of-args flag */
315  break;
316 
317  case 'B':
318  *argFlags |= DO_SELFTEST;
319  break;
320 
321  case 'C':
322  *argFlags |= DO_CONFIG;
323  break;
324 
325  case 'D':
326  *argFlags |= DO_DEVICE;
327  break;
328 
329  case 'E':
330  *argFlags |= DO_ENVELOPE;
331  break;
332 
333  case 'F':
334  *argFlags |= DO_KEYSETFILE;
335  break;
336 
337  case 'H':
338  usageExit();
339  break;
340 
341  case 'I':
342  *argFlags |= DO_HIGHLEVEL;
343  break;
344 
345  case 'K':
346  *argFlags |= DO_KEYSETDBX;
347  break;
348 
349  case 'L':
350  *argFlags |= DO_LOWLEVEL;
351  break;
352 
353  case 'M':
354  *argFlags |= DO_MIDLEVEL;
355  break;
356 
357  case 'O':
358  *argFlags |= DO_CONFIG;
359  break;
360 
361  case 'P':
362  *argFlags |= DO_CERTPROCESS;
363  break;
364 
365  case 'R':
366  *argFlags |= DO_RANDOM;
367  break;
368 
369  case 'S':
370  *argFlags |= DO_SESSION;
371  break;
372 
373  case 'T':
374  *argFlags |= DO_SESSIONLOOPBACK;
375  break;
376 
377  case 'U':
378  *argFlags |= DO_USER;
379  break;
380 
381  case 'Z':
382  zargPtr = argPtr + 1;
383  if( *zargPtr == '\0' )
384  {
385  puts( "Error: Missing argument for -z option." );
386  return( FALSE );
387  }
388  while( argPtr[ 1 ] )
389  argPtr++; /* Skip rest of arg */
390  *zargPtrPtr = zargPtr;
391  break;
392 
393  default:
394  printf( "Error: Unknown argument '%c'.\n", *argPtr );
395  return( FALSE );
396  }
397  argPtr++;
398  }
399  argv++;
400  argc--;
401  }
402  if( argc > 0 )
403  {
404  printf( "Error: Unknown argument '%s'.\n", argv[ 0 ] );
405  return( FALSE );
406  }
407 
408  return( TRUE );
409  }
410 
411 /****************************************************************************
412 * *
413 * Misc.Kludges *
414 * *
415 ****************************************************************************/
416 
417 /* Generic test code insertion point. The following routine is called
418  before any of the other tests are run and can be used to handle special-
419  case tests that aren't part of the main test suite */
420 
421 static void testKludge( const char *argPtr )
422  {
423 #if 0
425 #endif /* 0 */
426 
427  /* Performance-testing test harness */
428 #if 0
429  void performanceTests( const CRYPT_DEVICE cryptDevice );
430 
431  performanceTests( CRYPT_UNUSED );
432 #endif /* 0 */
433 
434  /* Memory diagnostic test harness */
435 #if 0
437  testEnvelopePKCCrypt(); /* Use "Datasize, certificate" */
438  testEnvelopeSign(); /* Use "Datasize, certificate" */
439 #endif /* 0 */
440 
441  /* Simple (brute-force) server code. NB: Remember to change
442  setLocalConnect() to not bind the server to localhost if expecting
443  external connections */
444 #if 0
445  while( TRUE )
447 #endif /* 0 */
448 
449  /* Shared exit point for the test harnesses above, used when we don't
450  want to fall through to the main test code */
451 #if 0
452  cryptEnd();
453  puts( "\nPress a key to exit." );
454  getchar();
455  exit( EXIT_SUCCESS );
456 #endif /* 0 */
457  }
458 
459 /****************************************************************************
460 * *
461 * Main Test Code *
462 * *
463 ****************************************************************************/
464 
465 /* Comprehensive cryptlib stress test. To get the following to run under
466  WinCE as a native console app it's necessary to change the entry point
467  in Settings | Link | Output from WinMainCRTStartup to the undocumented
468  mainACRTStartup, which calls main() rather than WinMain(), however this
469  only works if the system has a native console-mode driver (most don't) */
470 
471 int main( int argc, char **argv )
472  {
473  const char *zargPtr = NULL;
474  BOOLEAN sessionTestError = FALSE, loopbackTestError = FALSE;
475  int flags, status;
476  void testSystemSpecific1( void );
477  void testSystemSpecific2( void );
478 
479  /* If we're running in test mode, run the test code and exit */
480 #ifdef CONFIG_SUITEB_TESTS
481  return( suiteBMain( argc, argv ) );
482 #endif /* CONFIG_SUITEB_TESTS */
483 
484  /* Print a general banner to let the user know what's going on */
485  printf( "testlib - cryptlib %d-bit self-test framework.\n",
486  ( int ) sizeof( long ) * 8 ); /* Cast for gcc */
487  puts( "Copyright Peter Gutmann 1995 - 2011." );
488  puts( "" );
489 
490  /* Skip the program name and process any command-line arguments */
491  argv++; argc--;
492  status = processArgs( argc, argv, &flags, &zargPtr );
493  if( !status )
494  exit( EXIT_FAILURE );
495 
496 #ifdef USE_TCHECK
498 #endif /* USE_TCHECK */
499 
500  /* Make sure that various system-specific features are set right */
502 
503  /* VisualAge C++ doesn't set the TZ correctly. The check for this isn't
504  as simple as it would seem since most IBM compilers define the same
505  preprocessor values even though it's not documented anywhere, so we
506  have to enable the tzset() call for (effectively) all IBM compilers
507  and then disable it for ones other than VisualAge C++ */
508 #if ( defined( __IBMC__ ) || defined( __IBMCPP__ ) ) && !defined( __VMCMS__ )
509  tzset();
510 #endif /* VisualAge C++ */
511 
512  /* Initialise cryptlib */
513  printf( "Initialising cryptlib..." );
514  status = cryptInit();
515  if( cryptStatusError( status ) )
516  {
517  printf( "\ncryptInit() failed with error code %d, line %d.\n",
518  status, __LINE__ );
519  exit( EXIT_FAILURE );
520  }
521  puts( "done." );
522 
523 #ifndef TEST_RANDOM
524  /* In order to avoid having to do a randomness poll for every test run,
525  we bypass the randomness-handling by adding some junk. This is only
526  enabled when cryptlib is built in debug mode so it won't work with
527  any production systems */
528  #if defined( __MVS__ ) || defined( __VMCMS__ )
529  #pragma convlit( resume )
530  cryptAddRandom( "xyzzy", 5 );
531  #pragma convlit( suspend )
532  #else
533  cryptAddRandom( "xyzzy", 5 );
534  #endif /* Special-case EBCDIC handling */
535 #endif /* TEST_RANDOM */
536 
537  /* Perform a general sanity check to make sure that the self-test is
538  being run the right way */
539  if( !checkFileAccess() )
540  {
541  cryptEnd();
542  exit( EXIT_FAILURE );
543  }
544 
545  /* Make sure that further system-specific features that require cryptlib
546  to be initialised to check are set right */
547 #ifndef _WIN32_WCE
549 #endif /* WinCE */
550 
551 #ifdef USE_TCHECK
553 #endif /* USE_TCHECK */
554 
555  /* For general testing purposes we can insert test code at this point to
556  test special cases that aren't covered in the general tests below */
557  testKludge( zargPtr );
558 
559 #ifdef SMOKE_TEST
560  /* Perform a general smoke test of the kernel */
561  smokeTest();
562 #endif /* SMOKE_TEST */
563 
564  /* Test each block of cryptlib functionality */
565  if( ( flags & DO_SELFTEST ) && !testSelfTest() )
566  goto errorExit;
567  if( ( flags & DO_LOWLEVEL ) && !testLowLevel() )
568  goto errorExit;
569  if( ( flags & DO_RANDOM ) && !testRandom() )
570  goto errorExit;
571  if( ( flags & DO_CONFIG ) && !testConfig() )
572  goto errorExit;
573  if( ( flags & DO_DEVICE ) && !testDevice() )
574  goto errorExit;
575  if( ( flags & DO_MIDLEVEL ) && !testMidLevel() )
576  goto errorExit;
577  if( ( flags & DO_CERT ) && !testCert() )
578  goto errorExit;
579  if( ( flags & DO_KEYSETFILE ) && !testKeysetFile() )
580  goto errorExit;
581  if( ( flags & DO_KEYSETDBX ) && !testKeysetDatabase() )
582  goto errorExit;
583  if( ( flags & DO_CERTPROCESS ) && !testCertMgmt() )
584  goto errorExit;
585  if( ( flags & DO_HIGHLEVEL ) && !testHighLevel() )
586  goto errorExit;
587  if( ( flags & DO_ENVELOPE ) && !testEnveloping() )
588  goto errorExit;
589  if( ( flags & DO_SESSION ) && !testSessions() )
590  {
591  sessionTestError = TRUE;
592  goto errorExit;
593  }
594  if( ( flags & DO_SESSIONLOOPBACK ) && !testSessionsLoopback() )
595  {
596  loopbackTestError = TRUE;
597  goto errorExit;
598  }
599  if( ( flags & DO_USER ) && !testUsers() )
600  goto errorExit;
601 
602  /* Shut down cryptlib */
603  status = cryptEnd();
604  if( cryptStatusError( status ) )
605  {
606  if( status == CRYPT_ERROR_INCOMPLETE )
607  {
608  puts( "cryptEnd() failed with error code CRYPT_ERROR_INCOMPLETE, "
609  "a code path in the\nself-test code resulted in an error "
610  "return without a full cleanup of objects.\nIf you were "
611  "running the multithreaded loopback tests this may be "
612  "because one\nor more threads lost sync with other threads "
613  "and exited without cleaning up\nits objects. This "
614  "happens occasionally due to network timing issues or\n"
615  "thread scheduling differences." );
616  }
617  else
618  {
619  printf( "cryptEnd() failed with error code %d, line %d.\n",
620  status, __LINE__ );
621  }
622  goto errorExit1;
623  }
624 
625  puts( "All tests concluded successfully." );
626  return( EXIT_SUCCESS );
627 
628  /* All errors end up here */
629 errorExit:
630  cryptEnd();
631 errorExit1:
632  puts( "\nThe test was aborted due to an error being detected. If you "
633  "want to report\nthis problem, please provide as much information "
634  "as possible to allow it to\nbe diagnosed, for example the call "
635  "stack, the location inside cryptlib where\nthe problem occurred, "
636  "and the values of any variables that might be\nrelevant." );
637  if( sessionTestError )
638  {
639  puts( "\nThe error occurred during one of the network session tests, "
640  "if the error\nmessage indicates a network-level problem such "
641  "as ECONNREFUSED, ECONNRESET,\nor a timeout or read error then "
642  "this is either due to a transient\nnetworking problem or a "
643  "firewall interfering with network connections. This\nisn't a "
644  "cryptlib error, and doesn't need to be reported." );
645  }
646 #ifdef WINDOWS_THREADS
647  if( loopbackTestError )
648  {
649  puts( "\nThe error occurred during one of the multi-threaded network "
650  "loopback\ntests, this was probably due to the different threads "
651  "losing synchronisation.\nFor the secure sessions this usually "
652  "results in read/write, timeout, or\nconnection-closed errors "
653  "when one thread is pre-empted for too long. For the\n"
654  "certificate-management sessions it usually results in an error "
655  "related to the\nserver being pre-empted for too long by database "
656  "updates. Since the self-\ntest exists only to exercise "
657  "cryptlib's capabilities, it doesn't bother with\ncomplex thread "
658  "synchronisation during the multi-threaded loopback tests.\nThis "
659  "type of error is non-fatal, and should disappear if the test is "
660  "re-run." );
661  }
662 #endif /* WINDOWS_THREADS */
663 #if defined( __WINDOWS__ ) && !defined( NDEBUG )
664  /* The pseudo-CLI VC++ output windows are closed when the program exits
665  so we have to explicitly wait to allow the user to read them */
666  puts( "\nHit a key..." );
667  getchar();
668 #endif /* __WINDOWS__ && !NDEBUG */
669  return( EXIT_FAILURE );
670  }
671 
672 /* PalmOS wrapper for main() */
673 
674 #ifdef __PALMSOURCE__
675 
676 #include <CmnErrors.h>
677 #include <CmnLaunchCodes.h>
678 
679 uint32_t PilotMain( uint16_t cmd, void *cmdPBP, uint16_t launchFlags )
680  {
681  switch( cmd )
682  {
683  case sysAppLaunchCmdNormalLaunch:
684  main( 0, NULL );
685  }
686 
687  return( errNone );
688  }
689 #endif /* __PALMSOURCE__ */
690 
691 /* Symbian wrapper for main() */
692 
693 #ifdef __SYMBIAN__
694 
695 GLDEF_C TInt E32Main( void )
696  {
697  main( 0, NULL );
698 
699  return( KErrNone );
700  }
701 
702 #ifdef __WINS__
703 
704 /* Support functions for use under the Windows emulator */
705 
706 EXPORT_C TInt WinsMain( void )
707  {
708  E32Main();
709 
710  return( KErrNone );
711  }
712 
713 TInt E32Dll( TDllReason )
714  {
715  /* Entry point for the DLL loader */
716  return( KErrNone );
717  }
718 #endif /* __WINS__ */
719 
720 #endif /* __SYMBIAN__ */
721 
722 /* Test the system-specific defines in crypt.h. This is the last function in
723  the file because we want to avoid any definitions in crypt.h messing with
724  the rest of the test.c code.
725 
726  The following include is needed only so we can check whether the defines
727  are set right. crypt.h should never be included in a program that uses
728  cryptlib */
729 
730 #undef __WINDOWS__
731 #undef __WIN16__
732 #undef __WIN32__
733 #undef BOOLEAN
734 #undef BYTE
735 #undef FALSE
736 #undef TRUE
737 #undef FAR_BSS
738 #if defined( __MVS__ ) || defined( __VMCMS__ )
739  #pragma convlit( resume )
740 #endif /* Resume ASCII use on EBCDIC systems */
741 #if defined( __ILEC400__ )
742  #pragma convert( 819 )
743 #endif /* Resume ASCII use on EBCDIC systems */
744 #ifdef _MSC_VER
745  #include "../crypt.h"
746 #else
747  #include "crypt.h"
748 #endif /* Braindamaged MSC include handling */
749 #if defined( __MVS__ ) || defined( __VMCMS__ )
750  #pragma convlit( suspend )
751 #endif /* Suspend ASCII use on EBCDIC systems */
752 #if defined( __ILEC400__ )
753  #pragma convert( 0 )
754 #endif /* Suspend ASCII use on EBCDIC systems */
755 #undef mktime /* Undo mktime() bugfix in crypt.h */
756 
757 #ifndef _WIN32_WCE
758 
759 static time_t testTime( const int year )
760  {
761  struct tm theTime;
762 
763  memset( &theTime, 0, sizeof( struct tm ) );
764  theTime.tm_isdst = -1;
765  theTime.tm_year = 100 + year;
766  theTime.tm_mon = 5;
767  theTime.tm_mday = 5;
768  theTime.tm_hour = 12;
769  theTime.tm_min = 13;
770  theTime.tm_sec = 14;
771  return( mktime( &theTime ) );
772  }
773 #endif /* !WinCE */
774 
776  {
777 #if 0 /* See comment below */
778  const CRYPT_ATTRIBUTE_TYPE testType = -1;
779 #endif /* 0 */
780  int bigEndian;
781 #ifndef _WIN32_WCE
782  int i;
783 #endif /* WinCE */
784 
785  /* Make sure that we've got the endianness set right. If the machine is
786  big-endian (up to 64 bits) the following value will be signed,
787  otherwise it will be unsigned. We can't easily test for things like
788  middle-endianness without knowing the size of the data types, but
789  then again it's unlikely we're being run on a PDP-11 */
790  bigEndian = ( *( long * ) "\x80\x00\x00\x00\x00\x00\x00\x00" < 0 );
791 #ifdef DATA_LITTLEENDIAN
792  if( bigEndian )
793  {
794  puts( "The CPU endianness define is set wrong in crypt.h, this "
795  "machine appears to be\nbig-endian, not little-endian. Edit "
796  "the file and rebuild cryptlib." );
797  exit( EXIT_FAILURE );
798  }
799 #else
800  if( !bigEndian )
801  {
802  puts( "The CPU endianness define is set wrong in crypt.h, this "
803  "machine appears to be\nlittle-endian, not big-endian. Edit "
804  "the file and rebuild cryptlib." );
805  exit( EXIT_FAILURE );
806  }
807 #endif /* DATA_LITTLEENDIAN */
808 
809  /* Make sure that the compiler doesn't use variable-size enums (done by,
810  for example, the PalmOS SDK for backwards compatibility with
811  architectural decisions made for 68K-based PalmPilots) */
812  if( sizeof( CRYPT_ALGO_TYPE ) != sizeof( int ) || \
813  sizeof( CRYPT_MODE_TYPE ) != sizeof( int ) ||
814  sizeof( CRYPT_ATTRIBUTE_TYPE ) != sizeof( int ) )
815  {
816  puts( "The compiler you are using treats enumerated types as "
817  "variable-length non-\ninteger values, making it impossible "
818  "to reliably pass the address of an\nenum as a function "
819  "parameter. To fix this you need to rebuild cryptlib\nwith "
820  "the appropriate compiler option or pragma to ensure that\n"
821  "sizeof( enum ) == sizeof( int )." );
822  exit( EXIT_FAILURE );
823  }
824 
825 #if 0 /* The ANSI C default is 'int' with signedness being unimportant,
826  MSVC defaults to signed, gcc defaults to unsigned, and cryptlib
827  works with either, so whatever the CodeSourcery build of gcc is
828  doing it's more serious than a simple signedness issue */
829  /* Make sure that the compiler doesn't use unsigned enums (for example a
830  mutant CodeSourcery build of gcc for eCos does this) */
831  if( testType >= 0 )
832  {
833  puts( "The compiler you are using treats enumerated types as "
834  "unsigned values,\nmaking it impossible to reliably use enums "
835  "in conjunction with standard\n(signed) integers. To fix this "
836  "you need to rebuild cryptlib with the\nappropriate compiler "
837  "option or pragma to ensure that enumerated types\nare signed "
838  "like standard data types." );
839  exit( EXIT_FAILURE );
840  }
841 #endif /* 0 */
842 
843  /* Make sure that mktime() works properly (there are some systems on
844  which it fails well before 2038) */
845 #ifndef _WIN32_WCE
846  for( i = 10; i < 36; i ++ )
847  {
848  const time_t theTime = testTime( i );
849 
850  if( theTime < 0 )
851  {
852  printf( "Warning: This system has a buggy mktime() that can't "
853  "handle dates beyond %d.\n Some certificate tests "
854  "will fail, and long-lived CA certificates\n won't "
855  "be correctly imported.\nPress a key...\n", 2000 + i );
856  getchar();
857  break;
858  }
859  }
860 #endif /* !WinCE */
861 
862  /* If we're compiling under Unix with threading support, make sure the
863  default thread stack size is sensible. We don't perform the check for
864  UnixWare/SCO since this already has the workaround applied */
865 #if defined( UNIX_THREADS ) && !defined( __SCO_VERSION__ )
866  {
867  pthread_attr_t attr;
868  size_t stackSize;
869 
870  pthread_attr_init( &attr );
871  pthread_attr_getstacksize( &attr, &stackSize );
872  pthread_attr_destroy( &attr );
873  #if ( defined( sun ) && OSVERSION > 4 )
874  /* Slowaris uses a special-case value of 0 (actually NULL) to indicate
875  the default stack size of 1MB (32-bit) or 2MB (64-bit), so we have to
876  handle this specially */
877  if( stackSize < 32768 && stackSize != 0 )
878  #else
879  if( stackSize < 32768 )
880  #endif /* Slowaris special-case handling */
881  {
882  printf( "The pthread stack size is defaulting to %ld bytes, which is "
883  "too small for\ncryptlib to run in. To fix this, edit the "
884  "thread-creation function macro in\ncryptos.h and recompile "
885  "cryptlib.\n", ( long ) stackSize );
886  exit( EXIT_FAILURE );
887  }
888  }
889 #endif /* UNIX_THREADS */
890  }
891 
892 #ifndef _WIN32_WCE /* Windows CE doesn't support ANSI C time functions */
893 
895  {
896  CRYPT_CERTIFICATE cryptCert;
897  const time_t theTime = time( NULL ) - 5;
898  int status;
899 
900  /* Make sure that the cryptlib and non-cryptlib code use the same time_t
901  size (some systems are moving from 32- to 64-bit time_t, which can
902  lead to problems if the library and calling code are built with
903  different sizes) */
904  status = cryptCreateCert( &cryptCert, CRYPT_UNUSED,
906  if( cryptStatusError( status ) )
907  {
908  if( status == CRYPT_ERROR_NOTAVAIL )
909  {
910  puts( "Couldn't create certificate object for time sanity-check "
911  "because certificate\n" "use has been disabled, skipping "
912  "time sanity check...\n" );
913  return;
914  }
915  puts( "Couldn't create certificate object for time sanity-check." );
916  exit( EXIT_FAILURE );
917  }
919  &theTime, sizeof( time_t ) );
920  cryptDestroyCert( cryptCert );
921  if( status == CRYPT_ERROR_PARAM4 )
922  {
923  printf( "Warning: This compiler is using a %ld-bit time_t data type, "
924  "which appears to be\n different to the one that "
925  "was used when cryptlib was built. This\n situation "
926  "usually occurs when the compiler allows the use of both\n"
927  " 32- and 64-bit time_t data types and different "
928  "options were\n selected for building cryptlib and "
929  "the test app. To resolve this,\n ensure that both "
930  "cryptlib and the code that calls it use the same\n"
931  " time_t data type.\n",
932  ( long ) sizeof( time_t ) * 8 );
933  exit( EXIT_FAILURE );
934  }
935  }
936 #endif /* WinCE */