1 /****************************************************************************
2 *																			*
3 *					cryptlib Certificate Handling Test Routines				*
4 *						Copyright Peter Gutmann 1997-2013					*
5 *																			*
6 ****************************************************************************/
7 
8 #include "cryptlib.h"
9 #include "test/test.h"
10 
11 #if defined( __MVS__ ) || defined( __VMCMS__ )
12   /* Suspend conversion of literals to ASCII. */
13   #pragma convlit( suspend )
14 #endif /* IBM big iron */
15 #if defined( __ILEC400__ )
16   #pragma convert( 0 )
17 #endif /* IBM medium iron */
18 
19 /****************************************************************************
20 *																			*
21 *								Utility Routines							*
22 *																			*
23 ****************************************************************************/
24 
25 /* Handle various types of certificate-processing errors */
26 
handleCertImportError(const int errorCode,const int lineNo)27 static BOOLEAN handleCertImportError( const int errorCode, const int lineNo )
28 	{
29 	fprintf( outputStream, "cryptImportCert() failed with error "
30 			 "code %d, line %d.\n", errorCode, lineNo );
31 	return( FALSE );
32 	}
33 
34 /****************************************************************************
35 *																			*
36 *						Certificate Import Routines Test					*
37 *																			*
38 ****************************************************************************/
39 
40 /* Test certificate import code */
41 
handleCertError(const CRYPT_CERTIFICATE cryptCert,const int certNo)42 static BOOLEAN handleCertError( const CRYPT_CERTIFICATE cryptCert,
43 								const int certNo )
44 	{
45 	int errorLocus, status;
46 
47 	fprintf( outputStream, "\n" );
48 	status = cryptGetAttribute( cryptCert, CRYPT_ATTRIBUTE_ERRORLOCUS,
49 								&errorLocus );
50 	if( cryptStatusError( status ) )
51 		{
52 		puts( "Couldn't get error locus for certificate check failure." );
53 		return( FALSE );
54 		}
55 
56 	/* Make sure that we don't fail just because the certificate that we're
57 	   using as a test has expired */
58 	if( errorLocus == CRYPT_CERTINFO_VALIDTO )
59 		{
60 		fputs( "Warning: Validity check failed because the certificate "
61 			   "has expired.\n", outputStream );
62 		return( TRUE );
63 		}
64 
65 	/* RegTP CA certs are marked as non-CA certs, report the problem and
66 	   continue */
67 	if( certNo == 3 && errorLocus == CRYPT_CERTINFO_CA )
68 		{
69 		fputs( "Warning: Validity check failed due to RegTP CA certificate "
70 			   "incorrectly\n         marked as non-CA certificate.\n",
71 			   outputStream );
72 		return( TRUE );
73 		}
74 
75 	/* Certificate #26 has an invalid keyUsage for the key it contains, it's
76 	   used in order to check for the ability to handle a non-hole BIT
77 	   STRING in a location where a hole encoding is normally used so we
78 	   don't care about this particular problem */
79 	if( certNo == 25 && errorLocus == CRYPT_CERTINFO_KEYUSAGE )
80 		{
81 		fputs( "Warning: Validity check failed due to CA certificate with "
82 			   "incorrect\n         key usage field (this will be ignored "
83 			   "since the certificate\n         is used to test for other "
84 			   "error handling conditions).\n", outputStream );
85 		return( TRUE );
86 		}
87 
88 	return( FALSE );
89 	}
90 
certImport(const int certNo,const BOOLEAN isECC,const BOOLEAN isBase64)91 static int certImport( const int certNo, const BOOLEAN isECC,
92 					   const BOOLEAN isBase64 )
93 	{
94 	CRYPT_CERTIFICATE cryptCert;
95 	FILE *filePtr;
96 	BYTE buffer[ BUFFER_SIZE ];
97 	int count, value, status;
98 
99 	fprintf( outputStream, "Testing %scertificate #%d import...\n",
100 			 isECC ? "ECC " : isBase64 ? "base64 " : "", certNo );
101 	filenameFromTemplate( buffer, isECC ? ECC_CERT_FILE_TEMPLATE : \
102 								  isBase64 ? BASE64CERT_FILE_TEMPLATE : \
103 											 CERT_FILE_TEMPLATE, certNo );
104 	if( ( filePtr = fopen( buffer, "rb" ) ) == NULL )
105 		{
106 		puts( "Couldn't find certificate file for import test." );
107 		return( FALSE );
108 		}
109 	count = fread( buffer, 1, BUFFER_SIZE, filePtr );
110 	fclose( filePtr );
111 
112 	/* Import the certificate */
113 	status = cryptImportCert( buffer, count, CRYPT_UNUSED,
114 							  &cryptCert );
115 	if( status == CRYPT_ERROR_NOSECURE && !( isECC || isBase64 ) && \
116 		( certNo == 8 || certNo == 9 ) )	/* 9 = 512-bit, 10 = P12 512-bit */
117 		{
118 		/* Some older certs use totally insecure 512-bit keys and can't be
119 		   processed unless we deliberately allow insecure keys.
120 		   Unfortunately this also blocks out the certificate that's used to
121 		   check the ability to handle invalid PKCS #1 padding, since this
122 		   only uses a 512-bit key, but if necessary it can be tested by
123 		   lowering MIN_PKCSIZE when building cryptlib */
124 		fputs( "Warning: Certificate import failed because the certificate "
125 			   "uses a very short\n         (insecure) key.\n\n",
126 			   outputStream );
127 		return( TRUE );
128 		}
129 	if( status == CRYPT_ERROR_NOSECURE && isECC && \
130 		( certNo == 1 || certNo == 2 || certNo == 3 || certNo == 4 ) )
131 		{
132 		/* Some ECC certs are now showing the same problem as conventional
133 		   encryption certs */
134 		fputs( "Warning: ECC certificate import failed because the "
135 			   "certificate uses a short\n         (insecure) key.\n\n",
136 			   outputStream );
137 		return( TRUE );
138 		}
139 	if( status == CRYPT_ERROR_BADDATA && !( isECC || isBase64 ) \
140 		&& certNo == 3 )
141 		{
142 		fputs( "Warning: Certificate import failed for RegTP/Deutsche "
143 			   "Telekom CA\n         certificate with negative public-key "
144 			   "values.\n\n", outputStream );
145 		return( TRUE );
146 		}
147 	if( status == CRYPT_ERROR_NOTAVAIL && !( isECC || isBase64 ) \
148 		&& certNo == 3 )
149 		{
150 		/* This certificate uses RIPEMD-160 as its hash algorithm */
151 		fputs( "Warning: Certificate import failed because the certificate "
152 			   "uses an\n         obsolete algorithm no longer supported in "
153 			   "this build of cryptlib.\n\n", outputStream );
154 		return( TRUE );
155 		}
156 	if( status == CRYPT_ERROR_NOTAVAIL && !( isECC || isBase64 ) && \
157 		certNo == 20 )
158 		{
159 		/* This is an ECDSA certificate, the algorithm isn't enabled by
160 		   default */
161 		fputs( "Warning: Certificate import failed because the certificate "
162 			   "uses an\n         algorithm that isn't enabled in this build "
163 			   "of cryptlib.\n\n", outputStream );
164 		return( TRUE );
165 		}
166 	if( status == CRYPT_ERROR_BADDATA && !( isECC || isBase64 ) \
167 		&& certNo == 30 )
168 		{
169 		/* This certificate has has the algoID in the signature altered to
170 		   make it invalid, since this isn't covered by the signature it
171 		   isn't detected by many implementations */
172 		fputs( "Certificate import failed for certificate with manipulated "
173 			   "signature data.\n", outputStream );
174 		fputs( "  (This is the correct result for this test).\n",
175 			   outputStream );
176 		return( TRUE );
177 		}
178 	if( status == CRYPT_ERROR_BADDATA && isBase64 && \
179 		( certNo == 3 || certNo == 4 ) )
180 		{
181 		/* These certificates claim to be in PEM format but have a single
182 		   continuous block of base64 data, one with and one without
183 		   the base64 termination characters */
184 		fputs( "Certificate import failed for certificate with invalid PEM "
185 			   "encoding.\n", outputStream );
186 		fputs( "  (This is the correct result for this test).\n",
187 			   outputStream );
188 		return( TRUE );
189 		}
190 	if( cryptStatusError( status ) )
191 		{
192 		fprintf( outputStream, "cryptImportCert() for certificate #%d "
193 				 "failed with error code %d, line %d.\n", certNo,
194 				 status, __LINE__ );
195 		return( FALSE );
196 		}
197 	status = cryptGetAttribute( cryptCert, CRYPT_CERTINFO_SELFSIGNED,
198 								&value );
199 	if( cryptStatusError( status ) )
200 		{
201 		/* Sanity check to make sure that the certificate internal state is
202 		   consistent - this should never happen */
203 		printf( "Couldn't get certificate self-signed status, status %d, "
204 				"line %d.\n", status, __LINE__ );
205 		return( FALSE );
206 		}
207 	if( value )
208 		{
209 		fprintf( outputStream, "Certificate is self-signed, checking "
210 				 "signature... " );
211 		status = cryptCheckCert( cryptCert, CRYPT_UNUSED );
212 		if( cryptStatusError( status ) )
213 			{
214 			if( !handleCertError( cryptCert, certNo ) )
215 				{
216 				return( attrErrorExit( cryptCert, "cryptCheckCert()",
217 									   status, __LINE__ ) );
218 				}
219 			}
220 		else
221 			fputs( "signature verified.\n", outputStream );
222 		}
223 	else
224 		{
225 		fputs( "Certificate is signed, signature key unknown.\n",
226 			   outputStream );
227 		}
228 
229 	/* Print information on what we've got */
230 	if( !printCertInfo( cryptCert ) )
231 		return( FALSE );
232 
233 	/* Perform a dummy generalised extension read to make sure that nothing
234 	   goes wrong for this */
235 	status = cryptGetCertExtension( cryptCert, "1.2.3.4", &value, NULL, 0,
236 									&count );
237 	if( status != CRYPT_ERROR_NOTFOUND )
238 		{
239 		printf( "Read of dummy extension didn't fail with "
240 				"CRYPT_ERROR_NOTFOUND, status %d, line %d.\n", status,
241 				__LINE__ );
242 		return( FALSE );
243 		}
244 
245 	/* Clean up */
246 	cryptDestroyCert( cryptCert );
247 	fputs( "Certificate import succeeded.\n\n", outputStream );
248 	return( TRUE );
249 	}
250 
251 #if 0	/* Test rig for NISCC certificate data */
252 
253 static void importTestData( void )
254 	{
255 	int i;
256 
257 	for( i = 1; i <= 110000; i++ )
258 		{
259 		CRYPT_CERTIFICATE cryptCert;
260 		FILE *filePtr;
261 		BYTE buffer[ BUFFER_SIZE ];
262 		int count, status;
263 
264 		if( !( i % 100 ) )
265 			printf( "%06d\r", i );
266 /*		filenameFromTemplate( buffer, "/tmp/simple_client/%08d", i ); */
267 /*		filenameFromTemplate( buffer, "/tmp/simple_server/%08d", i ); */
268 		filenameFromTemplate( buffer, "/tmp/simple_rootca/%08d", i );
269 		if( ( filePtr = fopen( buffer, "rb" ) ) == NULL )
270 			break;
271 		count = fread( buffer, 1, BUFFER_SIZE, filePtr );
272 		fclose( filePtr );
273 		status = cryptImportCert( buffer, count, CRYPT_UNUSED,
274 								  &cryptCert );
275 		if( cryptStatusOK( status ) )
276 			cryptDestroyCert( cryptCert );
277 		}
278 	}
279 #endif /* 0 */
280 
testCertImport(void)281 int testCertImport( void )
282 	{
283 	int i;
284 
285 	for( i = 1; i <= 34; i++ )
286 		{
287 		if( !certImport( i, FALSE, FALSE ) )
288 			return( FALSE );
289 		}
290 	return( TRUE );
291 	}
292 
testCertImportECC(void)293 int testCertImportECC( void )
294 	{
295 	int i;
296 
297 	if( cryptQueryCapability( CRYPT_ALGO_ECDSA, NULL ) == CRYPT_ERROR_NOTAVAIL )
298 		{
299 		fputs( "ECC algorithm support appears to be disabled, skipping "
300 			   "processing of ECDSA\ncertificates.\n", outputStream );
301 		return( TRUE );
302 		}
303 
304 	for( i = 1; i <= 10; i++ )
305 		{
306 		if( !certImport( i, TRUE, FALSE ) )
307 			return( FALSE );
308 		}
309 	return( TRUE );
310 	}
311 
certReqImport(const int certNo)312 static int certReqImport( const int certNo )
313 	{
314 	CRYPT_CERTIFICATE cryptCert;
315 	FILE *filePtr;
316 	BYTE buffer[ BUFFER_SIZE ];
317 	int count, complianceValue, status;
318 
319 	fprintf( outputStream, "Testing certificate request #%d import...\n",
320 			 certNo );
321 	filenameFromTemplate( buffer, CERTREQ_FILE_TEMPLATE, certNo );
322 	if( ( filePtr = fopen( buffer, "rb" ) ) == NULL )
323 		{
324 		puts( "Couldn't find certificate file for import test." );
325 		return( FALSE );
326 		}
327 	count = fread( buffer, 1, BUFFER_SIZE, filePtr );
328 	fclose( filePtr );
329 
330 	/* Import the certificate request and check that the signature is valid */
331 	if( certNo == 3 )
332 		{
333 		/* Some of the requests are broken and we have to set the compliance
334 		   level to oblivious to handle them */
335 		( void ) cryptGetAttribute( CRYPT_UNUSED,
336 									CRYPT_OPTION_CERT_COMPLIANCELEVEL,
337 									&complianceValue );
338 		cryptSetAttribute( CRYPT_UNUSED, CRYPT_OPTION_CERT_COMPLIANCELEVEL,
339 						   CRYPT_COMPLIANCELEVEL_OBLIVIOUS );
340 		}
341 	status = cryptImportCert( buffer, count, CRYPT_UNUSED,
342 							  &cryptCert );
343 	if( certNo == 3 )
344 		{
345 		cryptSetAttribute( CRYPT_UNUSED, CRYPT_OPTION_CERT_COMPLIANCELEVEL,
346 						   complianceValue );
347 		}
348 #ifdef __UNIX__
349 	if( status == CRYPT_ERROR_NOTAVAIL || status == CRYPT_ERROR_BADDATA )
350 		{
351 		puts( "The certificate request import failed, probably because "
352 			  "you're using an\nolder version of unzip that corrupts "
353 			  "certain types of files when it\nextracts them.  To fix this, "
354 			  "you need to re-extract test/*.der without\nusing the -a "
355 			  "option to convert text files.\n" );
356 		return( TRUE );		/* Skip this test and continue */
357 		}
358 #endif /* __UNIX__ */
359 	if( status == CRYPT_ERROR_NOSECURE && certNo == 1 )
360 		{
361 		fputs( "Warning: Certificate request import failed because the "
362 			   "request uses a very short\n         (insecure) key.\n",
363 			   outputStream );
364 		return( TRUE );
365 		}
366 	if( cryptStatusError( status ) )
367 		return( handleCertImportError( status, __LINE__ ) );
368 	if( certNo == 5 )
369 		{
370 		fputs( "  (Skipping signature check because CRMF data is "
371 			   "unsigned).\n", outputStream );
372 		}
373 	else
374 		{
375 		fprintf( outputStream, "Checking signature... " );
376 		status = cryptCheckCert( cryptCert, CRYPT_UNUSED );
377 		if( cryptStatusError( status ) )
378 			return( attrErrorExit( cryptCert, "cryptCheckCert()", status,
379 								   __LINE__ ) );
380 		fputs( "signature verified.\n", outputStream );
381 		}
382 
383 	/* Print information on what we've got */
384 	if( !printCertInfo( cryptCert ) )
385 		return( FALSE );
386 
387 	/* Clean up */
388 	cryptDestroyCert( cryptCert );
389 	fputs( "Certificate request import succeeded.\n\n", outputStream );
390 	return( TRUE );
391 	}
392 
testCertReqImport(void)393 int testCertReqImport( void )
394 	{
395 	int i;
396 
397 	for( i = 1; i <= 7; i++ )
398 		{
399 		if( !certReqImport( i ) )
400 			return( FALSE );
401 		}
402 	return( TRUE );
403 	}
404 
405 #define LARGE_CRL_SIZE	45000	/* Large CRL is too big for std.buffer */
406 
crlImport(const int crlNo,BYTE * buffer)407 static int crlImport( const int crlNo, BYTE *buffer )
408 	{
409 	CRYPT_CERTIFICATE cryptCert;
410 	FILE *filePtr;
411 	int count, status;
412 
413 	filenameFromTemplate( buffer, CRL_FILE_TEMPLATE, crlNo );
414 	if( ( filePtr = fopen( buffer, "rb" ) ) == NULL )
415 		{
416 		printf( "Couldn't find CRL file for CRL #%d import test.\n", crlNo );
417 		return( FALSE );
418 		}
419 	count = fread( buffer, 1, LARGE_CRL_SIZE, filePtr );
420 	fclose( filePtr );
421 	fprintf( outputStream, "CRL #%d has size %d bytes.\n", crlNo, count );
422 
423 	/* Import the CRL.  Since CRL's don't include the signing certificate,
424 	   we can't (easily) check the signature on it */
425 	status = cryptImportCert( buffer, count, CRYPT_UNUSED,
426 							  &cryptCert );
427 	if( cryptStatusError( status ) )
428 		return( handleCertImportError( status, __LINE__ ) );
429 
430 	/* Print information on what we've got and clean up */
431 	if( !printCertInfo( cryptCert ) )
432 		return( FALSE );
433 	cryptDestroyCert( cryptCert );
434 
435 	return( TRUE );
436 	}
437 
testCRLImport(void)438 int testCRLImport( void )
439 	{
440 	BYTE *bufPtr;
441 	int i;
442 
443 	fputs( "Testing CRL import...\n", outputStream );
444 
445 	/* Since we're working with an unusually large certificate object we
446 	   have to dynamically allocate the buffer for it */
447 	if( ( bufPtr = malloc( LARGE_CRL_SIZE ) ) == NULL )
448 		{
449 		puts( "Out of memory." );
450 		return( FALSE );
451 		}
452 	for( i = 1; i <= 4; i++ )
453 		{
454 		if( !crlImport( i, bufPtr ) )
455 			{
456 			free( bufPtr );
457 			return( FALSE );
458 			}
459 		}
460 
461 	/* Clean up */
462 	free( bufPtr );
463 	fputs( "CRL import succeeded.\n\n", outputStream );
464 	return( TRUE );
465 	}
466 
isSingleCert(const CRYPT_CERTIFICATE cryptCertChain)467 static BOOLEAN isSingleCert( const CRYPT_CERTIFICATE cryptCertChain )
468 	{
469 	int value, status;
470 
471 	/* Check whether a certificate chain contains a single non-self-signed
472 	   certificate, which means that we can't perform a signature check on
473 	   it */
474 	status = cryptGetAttribute( cryptCertChain, CRYPT_CERTINFO_SELFSIGNED,
475 								&value );
476 	if( cryptStatusOK( status ) && value )
477 		{
478 		/* It's a self-signed certificate, we should be able to check this
479 		   chain */
480 		return( FALSE );
481 		}
482 	cryptSetAttribute( cryptCertChain, CRYPT_CERTINFO_CURRENT_CERTIFICATE,
483 					   CRYPT_CURSOR_FIRST );
484 	if( cryptSetAttribute( cryptCertChain,
485 						   CRYPT_CERTINFO_CURRENT_CERTIFICATE,
486 						   CRYPT_CURSOR_NEXT ) == CRYPT_ERROR_NOTFOUND )
487 		{
488 		/* There's only a single certificate in the chain and it's not self-
489 		   signed, we can't check it */
490 		return( TRUE );
491 		}
492 
493 	return( FALSE );
494 	}
495 
checkExpiredCertChain(const CRYPT_CERTIFICATE cryptCertChain)496 static int checkExpiredCertChain( const CRYPT_CERTIFICATE cryptCertChain )
497 	{
498 	int complianceValue, status;
499 
500 	fprintf( outputStream, "Warning: The certificate chain didn't verify "
501 			 "because one or more\n         certificates in it have "
502 			 "expired.  Trying again in oblivious\n         mode... " );
503 	( void ) cryptGetAttribute( CRYPT_UNUSED,
504 								CRYPT_OPTION_CERT_COMPLIANCELEVEL,
505 								&complianceValue );
506 	cryptSetAttribute( CRYPT_UNUSED, CRYPT_OPTION_CERT_COMPLIANCELEVEL,
507 					   CRYPT_COMPLIANCELEVEL_OBLIVIOUS );
508 	status = cryptCheckCert( cryptCertChain, CRYPT_UNUSED );
509 	cryptSetAttribute( CRYPT_UNUSED, CRYPT_OPTION_CERT_COMPLIANCELEVEL,
510 					   complianceValue );
511 
512 	return( status );
513 	}
514 
handleCertChainError(const CRYPT_CERTIFICATE cryptCertChain,const int certNo,const int errorCode)515 static BOOLEAN handleCertChainError( const CRYPT_CERTIFICATE cryptCertChain,
516 									 const int certNo, const int errorCode )
517 	{
518 	int trustValue = CRYPT_UNUSED, errorLocus, status;
519 
520 	/* If the chain contains a single non-CA certificate, we'll get a
521 	   parameter error since we haven't supplied a signing certificate */
522 	if( errorCode == CRYPT_ERROR_PARAM2 && isSingleCert( cryptCertChain ) )
523 		{
524 		/* There's only a single certificate present, we can't do much with
525 		   it */
526 		fputs( "\nCertificate chain contains only a single standalone "
527 			   "certificate, skipping\nsignature check...\n",
528 			   outputStream );
529 		return( TRUE );
530 		}
531 
532 	/* If it's not a problem with validity, we can't go any further */
533 	if( errorCode != CRYPT_ERROR_INVALID )
534 		{
535 		return( attrErrorExit( cryptCertChain, "cryptCheckCert()",
536 							   errorCode, __LINE__ ) );
537 		}
538 
539 	/* Check the nature of the problem */
540 	status = cryptGetAttribute( cryptCertChain, CRYPT_ATTRIBUTE_ERRORLOCUS,
541 								&errorLocus );
542 	if( cryptStatusError( status ) )
543 		{
544 		puts( "Couldn't get error locus for certificate check failure." );
545 		return( FALSE );
546 		}
547 
548 	/* Try to work around the error */
549 	status = errorCode;
550 	if( errorLocus == CRYPT_CERTINFO_TRUSTED_IMPLICIT || \
551 		errorLocus == CRYPT_CERTINFO_TRUSTED_USAGE )
552 		{
553 		/* The error occured because of a problem with the root certificate,
554 		   try again with an implicitly-trusted root */
555 		if( errorLocus == CRYPT_CERTINFO_TRUSTED_IMPLICIT )
556 			{
557 			fprintf( outputStream, "\nWarning: The certificate chain didn't "
558 					 "verify because it didn't end in a\n         trusted "
559 					 "root certificate.  Checking again using an "
560 					 "implicitly\n         trusted root... " );
561 			}
562 		else
563 			{
564 			fprintf( outputStream, "\nWarning: The certificate chain didn't "
565 					 "verify because the root certificate's\n         key "
566 					 "isn't enabled for this usage.  Checking again using "
567 					 "an\n         implicitly trusted root... " );
568 			}
569 		if( cryptStatusError( \
570 				setRootTrust( cryptCertChain, &trustValue, 1 ) ) )
571 			{
572 			fprintf( outputStream, "\nAttempt to make chain root implicitly "
573 					 "trusted failed, status = %d, line %d.\n", status,
574 					 __LINE__ );
575 			return( FALSE );
576 			}
577 		status = cryptCheckCert( cryptCertChain, CRYPT_UNUSED );
578 		if( status == CRYPT_ERROR_INVALID )
579 			{
580 			( void ) cryptGetAttribute( cryptCertChain,
581 										CRYPT_ATTRIBUTE_ERRORLOCUS,
582 										&errorLocus );
583 			}
584 		}
585 	if( errorLocus == CRYPT_CERTINFO_VALIDTO )
586 		{
587 		/* One (or more) certs in the chain have expired, try again with the
588 		   compliance level wound down to nothing */
589 		fputc( '\n', outputStream );
590 		status = checkExpiredCertChain( cryptCertChain );
591 		if( status == CRYPT_ERROR_PARAM2 && isSingleCert( cryptCertChain ) )
592 			{
593 			/* There's only a single certificate present, we can't do much
594 			   with it */
595 			fputs( "\nCertificate chain contains only a single standalone "
596 				   "certificate, skipping\nsignature check...\n",
597 				   outputStream );
598 			return( TRUE );
599 			}
600 		}
601 	if( errorLocus == CRYPT_CERTINFO_CERTIFICATE )
602 		{
603 		fputs( "\nCertificate chain is incomplete (one or more certificates "
604 			   "needed to\ncomplete the chain are missing), skipping "
605 			   "signature check...\n", outputStream );
606 		return( TRUE );
607 		}
608 
609 	/* If we changed settings, restore their original values */
610 	if( trustValue != CRYPT_UNUSED )
611 		setRootTrust( cryptCertChain, NULL, trustValue );
612 
613 	/* If we've got a long-enough chain, try again with the next-to-last
614 	   certificate marked as trusted */
615 	if( cryptStatusOK( status ) && certNo == 4 )
616 		{
617 		fputs( "signatures verified.\n", outputStream );
618 		fputs( "Checking again with an intermediate certificate marked as "
619 			   "trusted...\n", outputStream );
620 		status = cryptSetAttribute( cryptCertChain,
621 									CRYPT_CERTINFO_CURRENT_CERTIFICATE,
622 									CRYPT_CURSOR_LAST );
623 		if( cryptStatusOK( status ) )
624 			status = cryptSetAttribute( cryptCertChain,
625 										CRYPT_CERTINFO_CURRENT_CERTIFICATE,
626 										CRYPT_CURSOR_PREVIOUS );
627 		if( cryptStatusOK( status ) )
628 			status = cryptSetAttribute( cryptCertChain,
629 										CRYPT_CERTINFO_TRUSTED_IMPLICIT, 1 );
630 		if( cryptStatusError( status ) )
631 			return( status );
632 		status = cryptCheckCert( cryptCertChain, CRYPT_UNUSED );
633 		if( status == CRYPT_ERROR_INVALID )
634 			{
635 			( void ) cryptGetAttribute( cryptCertChain,
636 										CRYPT_ATTRIBUTE_ERRORLOCUS,
637 										&errorLocus );
638 			if( errorLocus == CRYPT_CERTINFO_VALIDTO )
639 				{
640 				/* One (or more) certs in the chain have expired, try again
641 				   with the compliance level wound down to nothing */
642 				status = checkExpiredCertChain( cryptCertChain );
643 				}
644 			}
645 		if( trustValue != CRYPT_UNUSED )
646 			{
647 			cryptSetAttribute( cryptCertChain,
648 							   CRYPT_CERTINFO_TRUSTED_IMPLICIT,
649 							   trustValue );
650 			}
651 		}
652 
653 	/* If the lowered-limits check still didn't work, it's an error */
654 	if( cryptStatusError( status ) )
655 		{
656 		fputc( '\n', outputStream );
657 		return( attrErrorExit( cryptCertChain, "cryptCheckCert()", status,
658 							   __LINE__ ) );
659 		}
660 
661 	fputs( "signatures verified.\n", outputStream );
662 	return( TRUE );
663 	}
664 
certChainImport(const int certNo,const BOOLEAN isBase64)665 static int certChainImport( const int certNo, const BOOLEAN isBase64 )
666 	{
667 	CRYPT_CERTIFICATE cryptCertChain;
668 	FILE *filePtr;
669 	BYTE buffer[ BUFFER_SIZE ];
670 	int count, value, status;
671 
672 	fprintf( outputStream, "Testing %scert chain #%d import...\n",
673 			 isBase64 ? "base64 " : "", certNo );
674 	filenameFromTemplate( buffer, isBase64 ? BASE64CERTCHAIN_FILE_TEMPLATE : \
675 											 CERTCHAIN_FILE_TEMPLATE, certNo );
676 	if( ( filePtr = fopen( buffer, "rb" ) ) == NULL )
677 		{
678 		puts( "Couldn't find certificate chain file for import test." );
679 		return( FALSE );
680 		}
681 	count = fread( buffer, 1, BUFFER_SIZE, filePtr );
682 	fclose( filePtr );
683 	if( count == BUFFER_SIZE )
684 		{
685 		puts( "The certificate buffer size is too small for the certificate "
686 			  "chain.  To fix\nthis, increase the BUFFER_SIZE value in "
687 			  "test/testcert.c and recompile the code." );
688 		return( TRUE );		/* Skip this test and continue */
689 		}
690 	fprintf( outputStream, "Certificate chain has size %d bytes.\n", count );
691 
692 	/* Import the certificate chain.  This assumes that the default certs are
693 	   installed as trusted certs, which is required for cryptCheckCert() */
694 	status = cryptImportCert( buffer, count, CRYPT_UNUSED,
695 							  &cryptCertChain );
696 	if( cryptStatusError( status ) )
697 		{
698 		/* If we failed on the RSA e=3 certificate, this is a valid result */
699 		if( certNo == 2 && status == CRYPT_ERROR_BADDATA )
700 			{
701 			fprintf( outputStream, "Import of certificate with invalid e=3 "
702 					 "key failed, line %d.\n", __LINE__ );
703 			fputs( "  (This is the correct result for this test).\n",
704 				   outputStream );
705 			return( TRUE );
706 			}
707 		return( handleCertImportError( status, __LINE__ ) );
708 		}
709 	if( certNo == 2 )
710 		{
711 		printf( "Import of certificate with invalid e=3 key succeeded when "
712 				"it should have\n  failed, line %d.\n", __LINE__ );
713 		return( FALSE );
714 		}
715 	status = cryptGetAttribute( cryptCertChain, CRYPT_CERTINFO_CERTTYPE,
716 								&value );
717 	if( cryptStatusError( status ) )
718 		return( attrErrorExit( cryptCertChain, "cryptGetAttribute()",
719 							   status, __LINE__ ) );
720 	if( certNo == 1 || certNo == 6 )
721 		{
722 		/* The first chain has length 1 so it should be imported as a
723 		   standard certificate */
724 		if( value != CRYPT_CERTTYPE_CERTIFICATE )
725 			{
726 			printf( "Imported object isn't a certificate, line %d.\n",
727 					__LINE__ );
728 			return( FALSE );
729 			}
730 		}
731 	else
732 		{
733 		if( value != CRYPT_CERTTYPE_CERTCHAIN )
734 			{
735 			printf( "Imported object isn't a certificate chain, line %d.\n",
736 					__LINE__ );
737 			return( FALSE );
738 			}
739 		}
740 	fprintf( outputStream, "Checking signatures... " );
741 	status = cryptCheckCert( cryptCertChain, CRYPT_UNUSED );
742 	if( cryptStatusError( status ) )
743 		{
744 		if( !handleCertChainError( cryptCertChain, certNo, status ) )
745 			return( FALSE );
746 		}
747 	else
748 		fputs( "signatures verified.\n", outputStream );
749 
750 	/* Display info on each certificate in the chain */
751 	if( !printCertChainInfo( cryptCertChain ) )
752 		return( FALSE );
753 
754 	/* Clean up */
755 	cryptDestroyCert( cryptCertChain );
756 	fputs( "Certificate chain import succeeded.\n\n", outputStream );
757 	return( TRUE );
758 	}
759 
testCertChainImport(void)760 int testCertChainImport( void )
761 	{
762 	int i;
763 
764 	for( i = 1; i <= 6; i++ )
765 		{
766 		if( !certChainImport( i, FALSE ) )
767 			return( FALSE );
768 		}
769 	return( TRUE );
770 	}
771 
testOCSPImport(void)772 int testOCSPImport( void )
773 	{
774 	CRYPT_CERTIFICATE cryptCert, cryptResponderCert;
775 	FILE *filePtr;
776 	BYTE buffer[ BUFFER_SIZE ];
777 	int count, status;
778 
779 	if( ( filePtr = fopen( convertFileName( OCSP_OK_FILE ), "rb" ) ) == NULL )
780 		{
781 		puts( "Couldn't find OCSP OK response file for import test." );
782 		return( FALSE );
783 		}
784 	fputs( "Testing OCSP OK response import...\n", outputStream );
785 	count = fread( buffer, 1, BUFFER_SIZE, filePtr );
786 	fclose( filePtr );
787 	fprintf( outputStream, "OCSP OK response has size %d bytes.\n", count );
788 
789 	/* Import the OCSP OK response.  Because of the choose-your-own-trust-
790 	   model status of the OCSP RFC we have to supply our own signature
791 	   check certificate to verify the response */
792 	status = cryptImportCert( buffer, count, CRYPT_UNUSED,
793 							  &cryptCert );
794 	if( cryptStatusError( status ) )
795 		return( handleCertImportError( status, __LINE__ ) );
796 	fprintf( outputStream, "Checking signature... " );
797 	status = importCertFile( &cryptResponderCert, OCSP_CA_FILE );
798 	if( cryptStatusOK( status ) )
799 		{
800 		status = cryptCheckCert( cryptCert, cryptResponderCert );
801 		cryptDestroyCert( cryptResponderCert );
802 		}
803 	if( cryptStatusError( status ) )
804 		return( attrErrorExit( cryptCert, "cryptCheckCert()", status,
805 							   __LINE__ ) );
806 	fputs( "signatures verified.\n", outputStream );
807 
808 	/* Print information on what we've got */
809 	if( !printCertInfo( cryptCert ) )
810 		return( FALSE );
811 	cryptDestroyCert( cryptCert );
812 
813 	/* Now import the OCSP revoked response.  This has a different CA
814 	   certificate than the OK response, to keep things simple we don't
815 	   bother with a sig check for this one */
816 	fputs( "Testing OCSP revoked response import...\n", outputStream );
817 	if( ( filePtr = fopen( convertFileName( OCSP_REV_FILE ), "rb" ) ) == NULL )
818 		{
819 		puts( "Couldn't find OCSP revoked response file for import test." );
820 		return( FALSE );
821 		}
822 	count = fread( buffer, 1, BUFFER_SIZE, filePtr );
823 	fclose( filePtr );
824 	fprintf( outputStream, "OCSP revoked response has size %d bytes.\n",
825 			 count );
826 	status = cryptImportCert( buffer, count, CRYPT_UNUSED,
827 							  &cryptCert );
828 	if( cryptStatusError( status ) )
829 		return( handleCertImportError( status, __LINE__ ) );
830 
831 	/* Print information on what we've got */
832 	if( !printCertInfo( cryptCert ) )
833 		return( FALSE );
834 
835 	/* Clean up */
836 	cryptDestroyCert( cryptCert );
837 	fputs( "OCSP import succeeded.\n\n", outputStream );
838 	return( TRUE );
839 	}
840 
testBase64CertImport(void)841 int testBase64CertImport( void )
842 	{
843 	int i;
844 
845 	/* If this is an EBCDIC system, we can't (easily) import the base64-
846 	   encoded certificate without complex calisthenics to handle the
847 	   different character sets */
848 #if 'A' == 0xC1
849 	puts( "Skipping import of base64-encoded data on EBCDIC system.\n" );
850 	return( TRUE );
851 #endif /* EBCDIC system */
852 
853 	for( i = 1; i <= 4; i++ )
854 		{
855 		if( !certImport( i, FALSE, TRUE ) )
856 			return( FALSE );
857 		}
858 	return( TRUE );
859 	}
860 
testBase64CertChainImport(void)861 int testBase64CertChainImport( void )
862 	{
863 	int i;
864 
865 	/* If this is an EBCDIC system, we can't (easily) import the base64-
866 	   encoded certificate without complex calisthenics to handle the
867 	   different character sets */
868 #if 'A' == 0xC1
869 	puts( "Skipping import of base64-encoded data on EBCDIC system.\n" );
870 	return( TRUE );
871 #endif /* EBCDIC system */
872 
873 	for( i = 1; i <= 1; i++ )
874 		if( !certChainImport( i, TRUE ) )
875 			return( FALSE );
876 	return( TRUE );
877 	}
878 
miscImport(const char * fileName,const char * description)879 static int miscImport( const char *fileName, const char *description )
880 	{
881 	CRYPT_CERTIFICATE cryptCert;
882 	FILE *filePtr;
883 	BYTE buffer[ BUFFER_SIZE ];
884 	int count, status;
885 
886 	if( ( filePtr = fopen( fileName, "rb" ) ) == NULL )
887 		{
888 		printf( "Couldn't find file for %s key import test.\n",
889 				description );
890 		return( FALSE );
891 		}
892 	count = fread( buffer, 1, BUFFER_SIZE, filePtr );
893 	fclose( filePtr );
894 
895 	/* Import the object.  Since this isn't a certificate we can't do much
896 	   more with it than this - this is only used to test the low-level
897 	   code and needs to be run inside a debugger, since the call always
898 	   fails (the data being imported isn't a certificate) */
899 	status = cryptImportCert( buffer, count, CRYPT_UNUSED,
900 							  &cryptCert );
901 	if( status != CRYPT_ERROR_BADDATA && status != CRYPT_ERROR_UNDERFLOW )
902 		{
903 		fprintf( outputStream, "cryptImportCert() for %s key failed with "
904 				 "error code %d, line %d.\n", description, status,
905 				 __LINE__ );
906 		return( FALSE );
907 		}
908 
909 	/* Clean up */
910 	cryptDestroyCert( cryptCert );
911 	return( TRUE );
912 	}
913 
testMiscImport(void)914 int testMiscImport( void )
915 	{
916 	BYTE buffer[ BUFFER_SIZE ];
917 	int i;
918 
919 	fputs( "Testing base64-encoded SSH/PGP key import...\n", outputStream );
920 	for( i = 1; i <= 2; i++ )
921 		{
922 		filenameFromTemplate( buffer, SSHKEY_FILE_TEMPLATE, i );
923 		if( !miscImport( buffer, "SSH" ) )
924 			return( FALSE );
925 		}
926 	for( i = 1; i <= 3; i++ )
927 		{
928 		filenameFromTemplate( buffer, PGPASCKEY_FILE_TEMPLATE, i );
929 		if( !miscImport( buffer, "PGP" ) )
930 			return( FALSE );
931 		}
932 	fputs( "Import succeeded.\n\n", outputStream );
933 	return( TRUE );
934 	}
935 
936 /* Test handling of certs that chain by DN but not by keyID */
937 
testNonchainCert(void)938 int testNonchainCert( void )
939 	{
940 	/* The EE certificate expired in November 2007 so unfortunately we can't
941 	   perform this test any more until we can obtain further broken
942 	   certs from DigiCert */
943 #if 0
944 	CRYPT_CERTIFICATE cryptLeafCert, cryptCACert;
945 	int value, status;
946 
947 	fputs( "Testing handling of incorrectly chained certs...\n",
948 		   outputStream );
949 
950 	/* Since this test requires the use of attributes that aren't decoded at
951 	   the default compliance level, we have to raise it a notch to make sure
952 	   that we get the certificate attributes necessary to sort out the
953 	   mess */
954 	cryptGetAttribute( CRYPT_UNUSED, CRYPT_OPTION_CERT_COMPLIANCELEVEL,
955 					   &value );
956 	if( value < CRYPT_COMPLIANCELEVEL_PKIX_PARTIAL )
957 		cryptSetAttribute( CRYPT_UNUSED, CRYPT_OPTION_CERT_COMPLIANCELEVEL,
958 						   CRYPT_COMPLIANCELEVEL_PKIX_PARTIAL );
959 
960 	/* Get the EE and incorrectly chained CA certs */
961 	status = importCertFile( &cryptLeafCert, NOCHAIN_EE_FILE );
962 	if( cryptStatusOK( status ) )
963 		status = importCertFile( &cryptCACert, NOCHAIN_CA_FILE );
964 	if( cryptStatusError( status ) )
965 		return( FALSE );
966 
967 	cryptSetAttribute( CRYPT_UNUSED, CRYPT_OPTION_CERT_COMPLIANCELEVEL,
968 					   value );
969 
970 	/* Check the EE certificate using the apparently-correct but actually
971 	   incorrect CA certificate and make sure that we get the correct error
972 	   message */
973 	status = cryptCheckCert( cryptLeafCert, cryptCACert );
974 	if( status != CRYPT_ERROR_SIGNATURE )
975 		{
976 		printf( "Sig.check of incorrectly chained certificate returned %d, "
977 				"should have been %d, line %d.\n", status,
978 				CRYPT_ERROR_SIGNATURE, __LINE__ );
979 		return( FALSE );
980 		}
981 
982 	/* Clean up */
983 	cryptDestroyCert( cryptLeafCert );
984 	cryptDestroyCert( cryptCACert );
985 
986 	fputs( "Handling of incorrectly chained certs succeeded.\n\n",
987 		   outputStream );
988 #endif /* 0 */
989 	return( TRUE );
990 	}
991 
992 /* Test certificate handling at various levels of compliance */
993 
testCertComplianceLevel(void)994 int testCertComplianceLevel( void )
995 	{
996 	CRYPT_CERTIFICATE cryptCert, cryptCaCert DUMMY_INIT;
997 	FILE *filePtr;
998 	BYTE buffer[ BUFFER_SIZE ];
999 	int count, value, status;
1000 
1001 	( void ) cryptGetAttribute( CRYPT_UNUSED,
1002 								CRYPT_OPTION_CERT_COMPLIANCELEVEL, &value );
1003 
1004 	/* Test import of a broken certificate.  The brokenness is an invalid
1005 	   authorityKeyIdentifier which is processed at level
1006 	   CRYPT_COMPLIANCELEVEL_PKIX_PARTIAL and above, so first we try it in
1007 	   CRYPT_COMPLIANCELEVEL_PKIX_PARTIAL mode, which should fail, and then
1008 	   again in oblivious mode, which should succeed */
1009 	fprintf( outputStream, "Testing certificate handling at various "
1010 			 "compliance levels (current = %d)...\n", value );
1011 	if( ( filePtr = fopen( convertFileName( BROKEN_CERT_FILE ), \
1012 						   "rb" ) ) == NULL )
1013 		{
1014 		puts( "Couldn't certificate for import test." );
1015 		return( FALSE );
1016 		}
1017 	count = fread( buffer, 1, BUFFER_SIZE, filePtr );
1018 	fclose( filePtr );
1019 	if( value < CRYPT_COMPLIANCELEVEL_PKIX_PARTIAL )
1020 		{
1021 		status = cryptSetAttribute( CRYPT_UNUSED,
1022 									CRYPT_OPTION_CERT_COMPLIANCELEVEL,
1023 									CRYPT_COMPLIANCELEVEL_PKIX_PARTIAL );
1024 		if( status == CRYPT_ERROR_PARAM3 )
1025 			{
1026 			puts( "(Couldn't set compliance level to "
1027 				  "CRYPT_COMPLIANCELEVEL_PKIX_PARTIAL, probably\n because "
1028 				  "cryptlib has been configured to not use this level, "
1029 				  "skipping this\n test...)" );
1030 			}
1031 		else
1032 			{
1033 			status = cryptImportCert( buffer, count, CRYPT_UNUSED,
1034 								  &cryptCert );
1035 			}
1036 		if( cryptStatusOK( status ) )
1037 			{
1038 			/* Import in CRYPT_COMPLIANCELEVEL_PKIX_PARTIAL mode should
1039 			   fail */
1040 			cryptSetAttribute( CRYPT_UNUSED,
1041 							   CRYPT_OPTION_CERT_COMPLIANCELEVEL, value );
1042 			printf( "cryptImportCert() of broken certificate succeeded when "
1043 					"it should have failed, line %d.\n", __LINE__ );
1044 			return( FALSE );
1045 			}
1046 		}
1047 	cryptSetAttribute( CRYPT_UNUSED, CRYPT_OPTION_CERT_COMPLIANCELEVEL,
1048 					   CRYPT_COMPLIANCELEVEL_STANDARD );
1049 	status = cryptImportCert( buffer, count, CRYPT_UNUSED,
1050 							  &cryptCert );
1051 	cryptSetAttribute( CRYPT_UNUSED, CRYPT_OPTION_CERT_COMPLIANCELEVEL,
1052 					   value );
1053 	if( cryptStatusError( status ) )
1054 		{
1055 		/* Import in standard mode should succeed */
1056 		return( handleCertImportError( status, __LINE__ ) );
1057 		}
1058 
1059 	/* Print information on what we've got.  This should only print info for
1060 	   the two basic extensions that are handled in oblivious mode  */
1061 	if( !printCertInfo( cryptCert ) )
1062 		return( FALSE );
1063 	cryptDestroyCert( cryptCert );
1064 
1065 	/* Test checking of an expired certificate using a broken CA certificate
1066 	   in oblivious mode (this checks chaining and the signature, but little
1067 	   else) */
1068 	status = importCertFile( &cryptCert, BROKEN_USER_CERT_FILE );
1069 	if( cryptStatusOK( status ) )
1070 		status = importCertFile( &cryptCaCert, BROKEN_CA_CERT_FILE );
1071 	if( cryptStatusError( status ) )
1072 		return( handleCertImportError( status, __LINE__ ) );
1073 	status = cryptCheckCert( cryptCert, cryptCaCert );
1074 	if( cryptStatusOK( status ) )
1075 		{
1076 		/* Checking in normal mode should fail */
1077 		fprintf( outputStream, "cryptCheckCert() of broken certificate "
1078 				 "succeeded when it should have failed, line %d.\n",
1079 				 __LINE__ );
1080 		return( FALSE );
1081 		}
1082 	cryptSetAttribute( CRYPT_UNUSED, CRYPT_OPTION_CERT_COMPLIANCELEVEL,
1083 					   CRYPT_COMPLIANCELEVEL_OBLIVIOUS );
1084 	status = cryptCheckCert( cryptCert, cryptCaCert );
1085 	cryptSetAttribute( CRYPT_UNUSED, CRYPT_OPTION_CERT_COMPLIANCELEVEL,
1086 					   value );
1087 	if( cryptStatusError( status ) )
1088 		{
1089 		/* Checking in oblivious mode should succeed */
1090 		fprintf( outputStream, "cryptCheckCert() of broken certificate "
1091 				 "failed when it should have succeeded, line %d.\n",
1092 				 __LINE__ );
1093 		return( FALSE );
1094 		}
1095 	cryptDestroyCert( cryptCaCert );
1096 	cryptDestroyCert( cryptCert );
1097 
1098 	/* Clean up */
1099 	fputs( "Certificate handling at different compliance levels "
1100 		   "succeeded.\n\n", outputStream );
1101 	return( TRUE );
1102 	}
1103 
1104 /* Test handling of chain verification with various combinations of trusted
1105    and untrusted certificates and chains */
1106 
checkChain(const CHAINTEST_CERT_TYPE leftCertType,const BOOLEAN leftCertTrusted,const CHAINTEST_CERT_TYPE rightCertType,const BOOLEAN rightCertTrusted,const BOOLEAN statusOK)1107 static int checkChain( const CHAINTEST_CERT_TYPE leftCertType,
1108 					   const BOOLEAN leftCertTrusted,
1109 					   const CHAINTEST_CERT_TYPE rightCertType,
1110 					   const BOOLEAN rightCertTrusted,
1111 					   const BOOLEAN statusOK )
1112 	{
1113 	CRYPT_CERTIFICATE leftCert, rightCert = CRYPT_UNUSED;
1114 	static const char *certNames[] = \
1115 		{ "no certificate", "leaf certificate", "issuer certificate",
1116 		  "root certificate", "certificate chain",
1117 		  "certificate chain (no root)", "certificate chain (no leaf)",
1118 		  "error", "error"
1119 		};
1120 	int status;
1121 
1122 	fprintf( outputStream, "Verifying %s%s using %s%s...\n",
1123 			 leftCertTrusted ? "trusted " : "",
1124 			 certNames[ leftCertType ], rightCertTrusted ? "trusted " : "",
1125 			 certNames[ rightCertType ] );
1126 
1127 	/* Import the test certificates/chains */
1128 	status = importCertFromTemplate( &leftCert, CHAINTEST_FILE_TEMPLATE,
1129 									 leftCertType );
1130 	if( cryptStatusOK( status ) && rightCertType != CHAINTEST_NOCERT )
1131 		{
1132 		status = importCertFromTemplate( &rightCert, CHAINTEST_FILE_TEMPLATE,
1133 										 rightCertType );
1134 		}
1135 	if( cryptStatusError( status ) )
1136 		{
1137 		fprintf( outputStream, "Certificate import for certificate chain "
1138 				 "test failed, status %d, line %d.\n", status, __LINE__ );
1139 		return( FALSE );
1140 		}
1141 
1142 	/* Apply any necessary trust settings */
1143 	if( leftCertTrusted )
1144 		{
1145 		if( leftCertType == CHAINTEST_CHAIN || \
1146 			leftCertType == CHAINTEST_CHAIN_NOROOT || \
1147 			leftCertType == CHAINTEST_CHAIN_NOLEAF )
1148 			{
1149 			/* If it's a chain then we have to make sure we set the trust on
1150 			   the top-level certificate in it */
1151 			cryptSetAttribute( leftCert, CRYPT_CERTINFO_CURRENT_CERTIFICATE,
1152 							   CRYPT_CURSOR_LAST );
1153 			}
1154 		status = setRootTrust( leftCert, NULL, 1 );
1155 		}
1156 	if( cryptStatusOK( status ) && rightCertTrusted )
1157 		{
1158 		if( rightCertType == CHAINTEST_CHAIN || \
1159 			rightCertType == CHAINTEST_CHAIN_NOROOT || \
1160 			rightCertType == CHAINTEST_CHAIN_NOLEAF )
1161 			{
1162 			/* If it's a chain then we have to make sure we set the trust on
1163 			   the top-level certificate in it */
1164 			cryptSetAttribute( rightCert, CRYPT_CERTINFO_CURRENT_CERTIFICATE,
1165 							   CRYPT_CURSOR_LAST );
1166 			}
1167 		status = setRootTrust( rightCert, NULL, 1 );
1168 		}
1169 	if( cryptStatusError( status ) )
1170 		{
1171 		fprintf( outputStream, "Couldn't make certificate/certificate chain "
1172 				 "trusted, status %d, line %d.\n", status, __LINE__ );
1173 		return( FALSE );
1174 		}
1175 
1176 	/* Check the left item with the right one */
1177 	status = cryptCheckCert( leftCert, rightCert );
1178 	if( cryptStatusOK( status ) )
1179 		{
1180 		if( !statusOK )
1181 			{
1182 			printf( "Check succeeded, should have failed, line %d.\n",
1183 					__LINE__ );
1184 			return( FALSE );
1185 			}
1186 		}
1187 	else
1188 		{
1189 		if( statusOK )
1190 			{
1191 			printErrorAttributeInfo( leftCert );
1192 			fprintf( outputStream, "Check failed, should have succeeded, "
1193 					 "line %d.\n", __LINE__ );
1194 			return( FALSE );
1195 			}
1196 		}
1197 
1198 	/* Clean up */
1199 	if( leftCertTrusted )
1200 		cryptSetAttribute( leftCert, CRYPT_CERTINFO_TRUSTED_IMPLICIT, 0 );
1201 	if( rightCertType != CHAINTEST_NOCERT && rightCertTrusted )
1202 		cryptSetAttribute( rightCert, CRYPT_CERTINFO_TRUSTED_IMPLICIT, 0 );
1203 	cryptDestroyCert( leftCert );
1204 	if( rightCertType != CHAINTEST_NOCERT )
1205 		cryptDestroyCert( rightCert );
1206 	fprintf( outputStream, "Certificate chain check succeeded.\n\n" );
1207 
1208 	return( TRUE );
1209 	}
1210 
testCertChainHandling(void)1211 int testCertChainHandling( void )
1212 	{
1213 	/* Leaf + issuer */
1214 	if( !checkChain( CHAINTEST_LEAF, FALSE, CHAINTEST_ISSUER, FALSE, TRUE ) )
1215 		return( FALSE );
1216 	if( !checkChain( CHAINTEST_LEAF, FALSE, CHAINTEST_ISSUER, TRUE, TRUE ) )
1217 		return( FALSE );
1218 
1219 	/* Standalone chain */
1220 	if( !checkChain( CHAINTEST_CHAIN, FALSE, CHAINTEST_NOCERT, FALSE, FALSE ) )
1221 		return( FALSE );
1222 	if( !checkChain( CHAINTEST_CHAIN, TRUE, CHAINTEST_NOCERT, FALSE, TRUE ) )
1223 		return( FALSE );
1224 
1225 	/* Chain + trusted root */
1226 	if( !checkChain( CHAINTEST_CHAIN, FALSE, CHAINTEST_ROOT, FALSE, FALSE ) )
1227 		return( FALSE );
1228 	if( !checkChain( CHAINTEST_CHAIN, FALSE, CHAINTEST_ROOT, TRUE, TRUE ) )
1229 		return( FALSE );
1230 
1231 	/* Leaf + trusted chain */
1232 	if( !checkChain( CHAINTEST_LEAF, FALSE, CHAINTEST_CHAIN, FALSE, FALSE ) )
1233 		return( FALSE );
1234 	if( !checkChain( CHAINTEST_LEAF, FALSE, CHAINTEST_CHAIN, TRUE, FALSE ) )
1235 		return( FALSE );
1236 
1237 	/* Leaf + trusted chain without leaf */
1238 	if( !checkChain( CHAINTEST_LEAF, FALSE, CHAINTEST_CHAIN_NOLEAF, FALSE, FALSE ) )
1239 		return( FALSE );
1240 	if( !checkChain( CHAINTEST_LEAF, FALSE, CHAINTEST_CHAIN_NOLEAF, TRUE, FALSE ) )
1241 		return( FALSE );
1242 
1243 	/* Chain without root + trusted root */
1244 	if( !checkChain( CHAINTEST_CHAIN_NOROOT, FALSE, CHAINTEST_ROOT, FALSE, FALSE ) )
1245 		return( FALSE );
1246 	if( !checkChain( CHAINTEST_CHAIN_NOROOT, FALSE, CHAINTEST_ROOT, TRUE, TRUE ) )
1247 		return( FALSE );
1248 
1249 	/* Chain without root + trusted chain without leaf */
1250 	if( !checkChain( CHAINTEST_CHAIN_NOROOT, FALSE, CHAINTEST_CHAIN_NOLEAF, FALSE, FALSE ) )
1251 		return( FALSE );
1252 	if( !checkChain( CHAINTEST_CHAIN_NOROOT, FALSE, CHAINTEST_CHAIN_NOLEAF, FALSE, FALSE ) )
1253 		return( FALSE );
1254 
1255 	return( TRUE );
1256 	}
1257 
1258 /****************************************************************************
1259 *																			*
1260 *							NIST Path-processing Test						*
1261 *																			*
1262 ****************************************************************************/
1263 
1264 /* Test path processing using the NIST PKI test suite.  This doesn't run all
1265    of the tests since some are somewhat redundant (e.g. path length
1266    constraints ending at certificate n in a chain vs.cert n+1 in a chain
1267    where both are well short of the constraint length) or require complex
1268    additional processing (e.g. CRL fetches) which it's difficult to
1269    automate */
1270 
1271 typedef struct {
1272 	const int fileMajor, fileMinor;	/* Major and minor number of file */
1273 	const BOOLEAN isValid;			/* Whether path is valid */
1274 	const BOOLEAN policyOptional;	/* Whether explicit policy optional */
1275 	} PATH_TEST_INFO;
1276 
1277 static const PATH_TEST_INFO FAR_BSS pathTestInfo[] = {
1278 	/* Signature verification */
1279 	/*   0 */ { 1, 1, TRUE },
1280 	/*   1 */ { 1, 2, FALSE },
1281 	/*   2 */ { 1, 3, FALSE },
1282 	/*   3 */ { 1, 4, TRUE },
1283 	/*   4 */ { 1, 6, FALSE },
1284 
1285 	/* Validity periods */
1286 	/*   5 */ { 2, 1, FALSE },
1287 	/*   6 */ { 2, 2, FALSE },
1288 	/* The second certificate in test 4.2.3 has a validFrom date of 1950
1289 	   which cryptlib rejects on import as being not even remotely valid (it
1290 	   can't even be represented in the ANSI/ISO C date format).  Supposedly
1291 	   half-century-old certs are symptomatic of severely broken software so
1292 	   rejecting this certificate is justified */
1293 /*	**  X ** { 2, 3, TRUE }, */
1294 	/*   7 */ { 2, 4, TRUE },
1295 	/*   8 */ { 2, 5, FALSE },
1296 	/*   9 */ { 2, 6, FALSE },
1297 	/*  10 */ { 2, 7, FALSE },
1298 	/*  11 */ { 2, 8, TRUE },
1299 
1300 	/* Name chaining */
1301 	/*  12 */ { 3, 1, FALSE },
1302 	/*  13 */ { 3, 2, FALSE },
1303 	/*  14 */ { 3, 6, TRUE },
1304 	/*  15 */ { 3, 7, TRUE },
1305 	/*  16 */ { 3, 8, TRUE },
1306 	/*  17 */ { 3, 9, TRUE },
1307 
1308 	/* 4 = CRLs */
1309 
1310 	/* oldWithNew / newWithOld */
1311 	/*  18 */ { 5, 1, TRUE },
1312 	/*  19 */ { 5, 3, TRUE },
1313 
1314 	/* Basic constraints */
1315 	/*  20 */ { 6, 1, FALSE },
1316 	/*  21 */ { 6, 2, FALSE },
1317 	/*  22 */ { 6, 3, FALSE },
1318 	/*  23 */ { 6, 4, TRUE },
1319 	/*  24 */ { 6, 5, FALSE },
1320 	/*  25 */ { 6, 6, FALSE },
1321 	/*  26 */ { 6, 7, TRUE },
1322 	/* The second-to-last certificate in the path sets a pathLenConstraint of
1323 	   zero with the next certificate being a CA certificate (there's no EE
1324 	   certificate present).  cryptlib treats this as invalid since it can
1325 	   never lead to a valid path once the EE certificate is added */
1326 	/*  27 */ { 6, 8, FALSE /* TRUE */ },
1327 	/*  28 */ { 6, 9, FALSE },
1328 	/*  29 */ { 6, 10, FALSE },
1329 
1330 	/*  30 */ { 6, 11, FALSE },
1331 	/*  31 */ { 6, 12, FALSE },
1332 	/*  32 */ { 6, 13, TRUE },
1333 	/* This has the same problem as 4.6.8 */
1334 	/*  33 */ { 6, 14, FALSE /* TRUE */ },
1335 	/* The following are 4.5.x-style oldWithNew / newWithOld but with path
1336 	   constraints */
1337 	/*  34 */ { 6, 15, TRUE },
1338 	/*  35 */ { 6, 16, FALSE },
1339 	/*  36 */ { 6, 17, TRUE },
1340 
1341 	/* Key usage */
1342 	/*  37 */ { 7, 1, FALSE },
1343 	/*  38 */ { 7, 2, FALSE },
1344 	/*  39 */ { 7, 3, TRUE },
1345 
1346 	/* Policies */
1347 	/*  40 */ { 8, 1, TRUE },
1348 	/*  41 */ { 8, 2, TRUE },
1349 	/* The first certificate asserts a policy that differs from that of all
1350 	   other certificates in the path.  If no explicit policy is required
1351 	   (by setting CRYPT_OPTION_REQUIREPOLICY to FALSE) it will verify,
1352 	   otherwise it won't */
1353 	/*  42 */ { 8, 3, TRUE, TRUE },	/* Policy optional */
1354 	/*  43 */ { 8, 3, FALSE },
1355 	/*  44 */ { 8, 4, FALSE },
1356 	/*  45 */ { 8, 5, FALSE },
1357 	/*  46 */ { 8, 6, TRUE },
1358 	/* The false -> true changes below (4.8.7, 4.8.8, 4.8.9) occur because
1359 	   cryptlib takes its initial policy from the first CA certificate with
1360 	   a policy that it finds.  This is due to real-world issues where re-
1361 	   parented certificate chains due to re-sold CA root keys end up with
1362 	   different policies in the root and the next-level-down pseudo-root
1363 	   and problems where the root is an extension-less X.509v1 certificate.
1364 	   The same issue crops up in the 4.10.* / 4.11.* tests further down */
1365 	/*  47 */ { 8, 7, /* FALSE */ TRUE },
1366 	/*  48 */ { 8, 8, /* FALSE */ TRUE },
1367 	/*  49 */ { 8, 9, /* FALSE */ TRUE },
1368 	/*  50 */ { 8, 10, TRUE },
1369 	/*  51 */ { 8, 11, TRUE },
1370 	/*  52 */ { 8, 12, FALSE },
1371 	/*  53 */ { 8, 13, TRUE },
1372 	/*  54 */ { 8, 14, TRUE },
1373 	/*  55 */ { 8, 15, TRUE },
1374 	/*  56 */ { 8, 20, TRUE },
1375 
1376 	/* Policy constraints.  For these tests policy handling is dictated by
1377 	   policy constraints so we don't require explicit policies */
1378 	/*  57 */ { 9, 1, TRUE },
1379 	/*  58 */ { 9, 2, TRUE, TRUE },
1380 	/* The NIST test value for this one is wrong.  RFC 3280 section 4.2.1.12
1381 	   says:
1382 
1383 		If the requireExplicitPolicy field is present, the value of
1384 		requireExplicitPolicy indicates the number of additional
1385 		certificates that may appear in the path before an explicit policy
1386 		is required for the entire path.  When an explicit policy is
1387 		required, it is necessary for all certificates in the path to
1388 		contain an acceptable policy identifier in the certificate policies
1389 		extension.
1390 
1391 	   Test 4.9.3 has requireExplicitPolicy = 4 in a chain of 4 certs for
1392 	   which the last one has no policy.  NIST claims this shouldn't
1393 	   validate, which is incorrect */
1394 	/*  59 */ { 9, 3, TRUE /* FALSE */, TRUE },
1395 	/*  60 */ { 9, 4, TRUE, TRUE },
1396 	/*  61 */ { 9, 5, FALSE, TRUE },
1397 	/*  62 */ { 9, 6, TRUE, TRUE },
1398 	/*  63 */ { 9, 7, FALSE, TRUE },
1399 	/*  64 */ { 9, 8, FALSE, TRUE },
1400 
1401 	/* 10, 11 = Policy mappings.  The false -> true changes below (4.10.2,
1402 	   4.10.4) occur because cryptlib takes its initial policy from the
1403 	   first CA certificate with a policy that it finds.  This is due to
1404 	   real-world issues where re-parented certificate chains due to re-sold
1405 	   CA root keys end up with different policies in the root and the next-
1406 	   level-down pseudo-root and problems where the root is an extension-
1407 	   less X.509v1 certificate */
1408 	/*  65 */ { 10, 1, TRUE },
1409 	/*  66 */ { 10, 2, /* FALSE */ TRUE },
1410 	/*  67 */ { 10, 3, TRUE },
1411 	/*  68 */ { 10, 4, /* FALSE */ TRUE },
1412 	/*  69 */ { 10, 5, TRUE },
1413 	/*  70 */ { 10, 6, TRUE },
1414 	/*  71 */ { 10, 7, FALSE },
1415 	/*  72 */ { 10, 8, FALSE },
1416 	/*  73 */ { 10, 9, TRUE },
1417 	/* The test for 4.10.10 is a special case because it contains  the
1418 	   retroactively triggered requireExplicitPolicy extension, see the long
1419 	   comment in chk_chn.c for a discussion of this, for now we just
1420 	   disable the check by recording it as a value-true check because even
1421 	   the standards committee can't explain why it does what it does */
1422 	/*  74 */ { 10, 10, /* FALSE */ TRUE },
1423 	/*  75 */ { 10, 11, TRUE },
1424 	/*  76 */ { 10, 12, TRUE },
1425 	/*  77 */ { 10, 13, TRUE },
1426 	/*  78 */ { 10, 14, TRUE },
1427 
1428 	/* Policy inhibitPolicy.  The false -> true changes below (4.11.1) are
1429 	   as for the 10.x tests */
1430 	/*  79 */ { 11, 1, /* FALSE */ TRUE },
1431 	/* The NIST test value for 4.11.2 is wrong, the top-level CA
1432 	   certificate sets inhibitPolicyMapping to 1, the mid-level CA
1433 	   certificate maps policy 1 to policy 3, and the EE certificte asserts
1434 	   policy 3, however at this point inhibitPolicyMapping is in effect
1435 	   and policy 3 is no longer valid */
1436 	/*  80 */ { 11, 2, /* TRUE */ FALSE },
1437 	/*  81 */ { 11, 3, FALSE },
1438 	/* The NIST test value for 4.11.4 is wrong for the same reason as for
1439 	   4.11.2, except that the point of failure is a second sub-CA rather
1440 	   than the EE */
1441 	/*  82 */ { 11, 4, /* TRUE */ FALSE },
1442 	/*  83 */ { 11, 5, FALSE },
1443 	/*  84 */ { 11, 6, FALSE },
1444 	/* The NIST test value for 4.11.7 is wrong for the same reason as for
1445 	   4.11.2, except that the mapping is from policy 1 to policy 2 instead
1446 	   of policy 3 */
1447 	/*  85 */ { 11, 7, /* TRUE */ FALSE },
1448 	/*  86 */ { 11, 8, FALSE },
1449 	/*  87 */ { 11, 9, FALSE },
1450 	/*  88 */ { 11, 10, FALSE },
1451 	/*  89 */ { 11, 11, FALSE },
1452 
1453 	/* Policy inhibitAny */
1454 	/*  90 */ { 12, 1, FALSE },
1455 	/*  91 */ { 12, 2, TRUE },
1456 	/*  92 */ { 12, 3, TRUE },
1457 	/*  93 */ { 12, 4, FALSE },
1458 	/*  94 */ { 12, 5, FALSE },
1459 	/*  95 */ { 12, 6, FALSE },
1460 	/* The NIST test results for 4.12.7 and 4.12.9 are wrong or more
1461 	   specifically the PKIX spec is wrong, contradicting itself in the body
1462 	   of the spec and the path-processing pseudocode in that there's no
1463 	   path-kludge exception for policy constraints in the body but there is
1464 	   one in the pseudocode.  Since these chains contain path-kludge certs
1465 	   the paths are invalid - they would only be valid if there was a path-
1466 	   kludge exception for inhibitAnyPolicy.  Note that 4.9.7 and 4.9.8
1467 	   have the same conditions for requireExplicitPolicy but this time the
1468 	   NIST test results go the other way.  So although the PKIX spec is
1469 	   wrong the NIST test is also wrong in that it applies an inconsistent
1470 	   interpretation of the contradictions in the PKIX spec */
1471 	/*  96 */ { 12, 7, FALSE /* TRUE */ },
1472 	/*  97 */ { 12, 8, FALSE },
1473 	/*  98 */ { 12, 9, FALSE /* TRUE */ },
1474 	/*  99 */ { 12, 10, FALSE },
1475 
1476 	/* Name constraints */
1477 	/* 100 */ { 13, 1, TRUE },
1478 	/* 101 */ { 13, 2, FALSE },
1479 	/* 102 */ { 13, 3, FALSE },
1480 	/* 103 */ { 13, 4, TRUE },
1481 	/* 104 */ { 13, 5, TRUE },
1482 	/* 105 */ { 13, 6, TRUE },
1483 	/* 106 */ { 13, 7, FALSE },
1484 	/* 107 */ { 13, 8, FALSE },
1485 	/* 108 */ { 13, 9, FALSE },
1486 	/* 109 */ { 13, 10, FALSE },
1487 	/* 110 */ { 13, 11, TRUE },
1488 	/* 111 */ { 13, 12, FALSE },
1489 	/* 112 */ { 13, 13, FALSE },
1490 	/* 113 */ { 13, 14, TRUE },
1491 	/* 114 */ { 13, 15, FALSE },
1492 	/* 115 */ { 13, 16, FALSE },
1493 	/* 116 */ { 13, 17, FALSE },
1494 	/* 117 */ { 13, 18, TRUE },
1495 	/* 118 */ { 13, 19, TRUE },
1496 	/* 119 */ { 13, 20, FALSE },
1497 	/* 120 */ { 13, 21, TRUE },
1498 	/* 121 */ { 13, 22, FALSE },
1499 	/* 122 */ { 13, 23, TRUE },
1500 	/* 123 */ { 13, 24, FALSE },
1501 	/* 124 */ { 13, 25, TRUE },
1502 	/* 125 */ { 13, 26, FALSE },
1503 	/* 126 */ { 13, 27, TRUE },
1504 	/* 127 */ { 13, 28, FALSE },
1505 	/* 188 */ { 13, 29, FALSE },
1506 	/* 129 */ { 13, 30, TRUE },
1507 	/* 130 */ { 13, 31, FALSE },
1508 	/* 131 */ { 13, 32, TRUE },
1509 	/* 132 */ { 13, 33, FALSE },
1510 	/* 133 */ { 13, 34, TRUE },
1511 	/* 134 */ { 13, 35, FALSE },
1512 	/* 135 */ { 13, 36, TRUE },
1513 	/* 136 */ { 13, 37, FALSE },
1514 	/* The NIST test results for 4.13.38 are wrong.  PKIX section 4.2.1.11
1515 	   says:
1516 
1517 		DNS name restrictions are expressed as foo.bar.com.  Any DNS name
1518 		that can be constructed by simply adding to the left hand side of
1519 		the name satisfies the name constraint.  For example,
1520 		www.foo.bar.com would satisfy the constraint but foo1.bar.com would
1521 		not.
1522 
1523 	   The permitted subtree is testcertificates.gov and the altName is
1524 	   mytestcertificates.gov which satisfies the above rule so the path
1525 	   should be valid and not invalid */
1526 	/* 137 */ { 13, 38, TRUE /* FALSE */ },
1527 
1528 	/* 14, 15 = CRLs */
1529 
1530 	/* Private certificate extensions */
1531 	/* 138 */ { 16, 1, TRUE },
1532 	/* 139 */ { 16, 2, FALSE },
1533 	{ 0, 0 }
1534 	};
1535 
testPath(const PATH_TEST_INFO * pathInfo)1536 static int testPath( const PATH_TEST_INFO *pathInfo )
1537 	{
1538 	CRYPT_CERTIFICATE cryptCertPath;
1539 	char pathName[ 64 ];
1540 	int pathNo, requirePolicy, status;
1541 
1542 	/* Convert the composite path info into a single number used for fetching
1543 	   the corresponding data file */
1544 	sprintf( pathName, "4%d%d", pathInfo->fileMajor, pathInfo->fileMinor );
1545 	pathNo = atoi( pathName );
1546 
1547 	/* Test the path */
1548 	sprintf( pathName, "4.%d.%d", pathInfo->fileMajor, pathInfo->fileMinor );
1549 	fprintf( outputStream, "  Path %s%s...", pathName,
1550 			 pathInfo->policyOptional ? " without explicit policy" : "" );
1551 	status = importCertFromTemplate( &cryptCertPath,
1552 									 PATHTEST_FILE_TEMPLATE, pathNo );
1553 	if( cryptStatusError( status ) )
1554 		{
1555 		fprintf( outputStream, "Certificate import for test path %s failed, "
1556 				 "status %d, line %d.\n", pathName, status, __LINE__ );
1557 		return( FALSE );
1558 		}
1559 	if( pathInfo->policyOptional )
1560 		{
1561 		/* By default we require policy chaining, for some tests we can turn
1562 		   this off to check non-explict policy processing */
1563 		status = cryptGetAttribute( CRYPT_UNUSED,
1564 									CRYPT_OPTION_CERT_REQUIREPOLICY,
1565 									&requirePolicy );
1566 		assert( cryptStatusOK( status ) && requirePolicy != FALSE );
1567 		cryptSetAttribute( CRYPT_UNUSED, CRYPT_OPTION_CERT_REQUIREPOLICY,
1568 						   FALSE );
1569 		status = cryptCheckCert( cryptCertPath, CRYPT_UNUSED );
1570 		cryptSetAttribute( CRYPT_UNUSED, CRYPT_OPTION_CERT_REQUIREPOLICY,
1571 						   requirePolicy );
1572 		}
1573 	else
1574 		status = cryptCheckCert( cryptCertPath, CRYPT_UNUSED );
1575 	if( pathInfo->isValid )
1576 		{
1577 		if( cryptStatusError( status ) )
1578 			{
1579 			puts( " didn't verify even though it should be valid." );
1580 			return( attrErrorExit( cryptCertPath, "cryptCheckCert()",
1581 								   status, __LINE__ ) );
1582 			}
1583 		}
1584 	else
1585 		{
1586 		if( cryptStatusOK( status ) )
1587 			{
1588 			puts( " verified even though it should have failed." );
1589 			return( FALSE );
1590 			}
1591 		}
1592 	fputs( " succeeded.\n", outputStream );
1593 	cryptDestroyCert( cryptCertPath );
1594 
1595 	return( TRUE );
1596 	}
1597 
testPathProcessing(void)1598 int testPathProcessing( void )
1599 	{
1600 	CRYPT_CERTIFICATE cryptRootCert;
1601 	int certTrust DUMMY_INIT, complianceLevel, i, status;
1602 
1603 	fputs( "Testing path processing...\n", outputStream );
1604 
1605 	/* Get the root certificate and make it implicitly trusted and crank the
1606 	   compliance level up to maximum, since we're going to be testing some
1607 	   pretty obscure extensions */
1608 	status = importCertFromTemplate( &cryptRootCert,
1609 									 PATHTEST_FILE_TEMPLATE, 0 );
1610 	if( cryptStatusOK( status ) )
1611 		status = setRootTrust( cryptRootCert, &certTrust, 1 );
1612 	if( cryptStatusError( status ) )
1613 		{
1614 		fprintf( outputStream, "Couldn't create trusted root certificate "
1615 				 "for path processing, line %d.\n", __LINE__ );
1616 		return( FALSE );
1617 		}
1618 	( void ) cryptGetAttribute( CRYPT_UNUSED,
1619 								CRYPT_OPTION_CERT_COMPLIANCELEVEL,
1620 								&complianceLevel );
1621 	status = cryptSetAttribute( CRYPT_UNUSED,
1622 								CRYPT_OPTION_CERT_COMPLIANCELEVEL,
1623 								CRYPT_COMPLIANCELEVEL_PKIX_FULL );
1624 	if( cryptStatusError( status ) )
1625 		{
1626 		printf( "Couldn't set compliance level to "
1627 				"CRYPT_COMPLIANCELEVEL_PKIX_FULL, line %d.\nThis may be "
1628 				"because cryptlib has been configured not to run at this "
1629 				"level.\n", __LINE__ );
1630 		return( FALSE );
1631 		}
1632 
1633 	/* Process each certificate path and make sure that it succeeds or fails
1634 	   as required */
1635 	for( i = 0; pathTestInfo[ i ].fileMajor != 0; i++ )
1636 		{
1637 		if( !testPath( &pathTestInfo[ i ] ) )
1638 			break;
1639 		}
1640 	setRootTrust( cryptRootCert, NULL, certTrust );
1641 	cryptDestroyCert( cryptRootCert );
1642 	cryptSetAttribute( CRYPT_UNUSED, CRYPT_OPTION_CERT_COMPLIANCELEVEL,
1643 					   complianceLevel );
1644 	if( pathTestInfo[ i ].fileMajor )
1645 		return( FALSE );
1646 
1647 	fputs( "Path processing succeeded.\n", outputStream );
1648 	return( TRUE );
1649 	}
1650 
1651 /****************************************************************************
1652 *																			*
1653 *							Miscellaneous Tests								*
1654 *																			*
1655 ****************************************************************************/
1656 
1657 /* Test handling of invalid PKCS #1 padding in certificate signatures.  Note
1658    that running this test properly requires disabling the PKCS#1 padding
1659    format check in decodePKCS1() in mechs/mech_sig.c since the signatures
1660    have such an obviously dodgy format that they don't even make it past the
1661    basic padding sanity check */
1662 
testPKCS1Padding(void)1663 int testPKCS1Padding( void )
1664 	{
1665 	CRYPT_CERTIFICATE cryptCert;
1666 	int i, complianceValue, status;
1667 
1668 	fputs( "Testing invalid PKCS #1 padding handling...\n", outputStream );
1669 
1670 	/* The test certs don't have a keyUsage present in a CA certificate so
1671 	   we have to lower the compliance level to be able to get past this
1672 	   check to the signatures */
1673 	( void ) cryptGetAttribute( CRYPT_UNUSED,
1674 								CRYPT_OPTION_CERT_COMPLIANCELEVEL,
1675 								&complianceValue );
1676 	cryptSetAttribute( CRYPT_UNUSED, CRYPT_OPTION_CERT_COMPLIANCELEVEL,
1677 					   CRYPT_COMPLIANCELEVEL_OBLIVIOUS );
1678 	for( i = 1; i <= 11; i++ )
1679 		{
1680 		status = importCertFromTemplate( &cryptCert, PADTEST_FILE_TEMPLATE,
1681 										 i );
1682 		if( cryptStatusError( status ) )
1683 			{
1684 			fprintf( outputStream, "Couldn't import certificate for PKCS #1 "
1685 					 "padding check, status %d, line %d.\n", status,
1686 					 __LINE__ );
1687 			return( FALSE );
1688 			}
1689 		status = cryptCheckCert( cryptCert, CRYPT_UNUSED );
1690 		if( cryptStatusOK( status ) )
1691 			{
1692 			printf( "Certificate with bad PKSC #1 padding verified, should "
1693 					"have failed, line %d.\n", __LINE__ );
1694 			return( FALSE );
1695 			}
1696 		cryptDestroyCert( cryptCert );
1697 		}
1698 	cryptSetAttribute( CRYPT_UNUSED, CRYPT_OPTION_CERT_COMPLIANCELEVEL,
1699 					   complianceValue );
1700 
1701 	fputs( "Padding handling succeeded (all certs rejected).\n\n",
1702 		   outputStream );
1703 	return( TRUE );
1704 	}
1705 
1706 /* Generic test routines used for debugging.  These are only meant to be
1707    used interactively, and throw exceptions rather than returning status
1708    values */
1709 
xxxCertImport(const char * fileName)1710 int xxxCertImport( const char *fileName )
1711 	{
1712 	CRYPT_CERTIFICATE cryptCert;
1713 	FILE *filePtr;
1714 	BYTE buffer[ BUFFER_SIZE ], *bufPtr = buffer;
1715 	long length, count;
1716 	int status;
1717 
1718 	filePtr = fopen( fileName, "rb" );
1719 	assert( filePtr != NULL );
1720 	fseek( filePtr, 0L, SEEK_END );
1721 	length = ftell( filePtr );
1722 	fseek( filePtr, 0L, SEEK_SET );
1723 	if( length > BUFFER_SIZE )
1724 		{
1725 		bufPtr = malloc( length );
1726 		assert( bufPtr != NULL );
1727 		}
1728 	count = fread( bufPtr, 1, length, filePtr );
1729 	assert( count == length );
1730 	fclose( filePtr );
1731 	status = cryptImportCert( bufPtr, count, CRYPT_UNUSED, &cryptCert );
1732 	if( cryptStatusError( status ) )
1733 		{
1734 		fprintf( outputStream, "Certificate import failed, status = %d.\n",
1735 				 status );
1736 		assert( cryptStatusOK( status ) );
1737 		if( bufPtr != buffer )
1738 			free( bufPtr );
1739 		return( FALSE );
1740 		}
1741 	if( bufPtr != buffer )
1742 		free( bufPtr );
1743 	printCertChainInfo( cryptCert );
1744 	status = cryptCheckCert( cryptCert, CRYPT_UNUSED );	/* Opportunistic only */
1745 	if( cryptStatusError( status ) )
1746 		{
1747 		fprintf( outputStream, "(Opportunistic) certificate check failed, "
1748 				 "status = %d.\n", status );
1749 		printErrorAttributeInfo( cryptCert );
1750 		}
1751 	cryptDestroyCert( cryptCert );
1752 
1753 	return( cryptStatusOK( status ) ? TRUE : FALSE );
1754 	}
1755 
xxxCertCheck(const C_STR certFileName,const C_STR caFileNameOpt)1756 int xxxCertCheck( const C_STR certFileName, const C_STR caFileNameOpt )
1757 	{
1758 	CRYPT_CERTIFICATE cryptCert, cryptCaCert;
1759 	int status;
1760 
1761 	status = importCertFile( &cryptCert, certFileName );
1762 	if( cryptStatusError( status ) )
1763 		{
1764 		fprintf( outputStream, "Certificate import failed, status = %d.\n",
1765 				 status );
1766 		assert( cryptStatusOK( status ) );
1767 		return( FALSE );
1768 		}
1769 	if( caFileNameOpt == NULL )
1770 		{
1771 		/* It's a self-signed certificate or certificate chain, make it
1772 		   implicitly trusted in order to allow the signature check to
1773 		   work */
1774 		cryptCaCert = CRYPT_UNUSED;
1775 		status = cryptSetAttribute( cryptCert,
1776 									CRYPT_CERTINFO_CURRENT_CERTIFICATE,
1777 									CRYPT_CURSOR_LAST );
1778 		if( cryptStatusOK( status ) )
1779 			{
1780 			status = cryptSetAttribute( cryptCert,
1781 										CRYPT_CERTINFO_TRUSTED_IMPLICIT, 1 );
1782 			}
1783 		assert( cryptStatusOK( status ) );
1784 		}
1785 	else
1786 		{
1787 		status = importCertFile( &cryptCaCert, caFileNameOpt );
1788 		if( cryptStatusError( status ) )
1789 			{
1790 			fprintf( outputStream, "Couldn't import certificate from '%s', "
1791 					 "status = %d.\n", caFileNameOpt, status );
1792 			cryptDestroyCert( cryptCert );
1793 			return( FALSE );
1794 			}
1795 		}
1796 	status = cryptCheckCert( cryptCert, cryptCaCert );
1797 	if( cryptStatusError( status ) )
1798 		{
1799 		fprintf( outputStream, "Certificate check failed, status = %d.\n",
1800 				 status );
1801 		printErrorAttributeInfo( cryptCert );
1802 		}
1803 //	assert( cryptStatusOK( status ) );
1804 	cryptDestroyCert( cryptCert );
1805 	cryptDestroyCert( cryptCaCert );
1806 
1807 	return( cryptStatusOK( status ) ? TRUE : FALSE );
1808 	}
1809