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