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