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 /* Various features can be disabled by configuration options, in order to
12 handle this we need to include the cryptlib config file so that we can
13 selectively disable some tests */
14
15 #ifdef __WINDOWS__
16 /* For checking for debug-only capabilities */
17 #define _OSSPEC_DEFINED
18 #define VC_LT_2005( version ) ( version < 1400 )
19 #endif /* __WINDOWS__ */
20 #include "misc/config.h"
21
22 #if defined( __MVS__ ) || defined( __VMCMS__ )
23 /* Suspend conversion of literals to ASCII. */
24 #pragma convlit( suspend )
25 #endif /* IBM big iron */
26 #if defined( __ILEC400__ )
27 #pragma convert( 0 )
28 #endif /* IBM medium iron */
29
30 /* Certificate times. Note that this value must be greater than the value
31 defined by the kernel as MIN_TIME_VALUE, the minimum allowable
32 (backdated) timestamp value.
33
34 Unlike every other system on the planet, the Mac Classic takes the time_t
35 epoch as 1904 rather than 1970 (even VMS, MVS, VM/CMS, the AS/400, Tandem
36 NSK, and God knows what other sort of strangeness stick to 1970 as the
37 time_t epoch) so we have to add an offset of 2082844800L to adjust for
38 this. ANSI and ISO C are very careful to avoid specifying what the epoch
39 actually is, so it's legal to do this in the same way that it's legal for
40 Microsoft to break Kerberos because the standard doesn't say they can't.
41
42 Note that the Y2K time-test value isn't really used any more because Y2K
43 has long since come and gone, but it's left in here for historical
44 reasons in case someone has some checkbox requirement for something like
45 this */
46
47 #define ONE_YEAR_TIME ( 365 * 86400L )
48 #if defined( __MWERKS__ ) || defined( SYMANTEC_C ) || defined( __MRC__ )
49 #define CERTTIME_DATETEST ( ( ( 2016 - 1970 ) * ONE_YEAR_TIME ) + 2082844800L )
50 #define CERTTIME_Y2KTEST ( ( ( 2020 - 1970 ) * ONE_YEAR_TIME ) + 2082844800L )
51 #else
52 #define CERTTIME_DATETEST ( ( 2016 - 1970 ) * ONE_YEAR_TIME )
53 #define CERTTIME_Y2KTEST ( ( 2020 - 1970 ) * ONE_YEAR_TIME )
54 #endif /* Macintosh-specific weird epoch */
55 #include "misc/consts.h"
56 #if CERTTIME_DATETEST <= MIN_TIME_VALUE
57 #error CERTTIME_DATETEST must be > MIN_TIME_VALUE
58 #endif /* Safety check of time test value against MIN_TIME_VALUE */
59
60 /****************************************************************************
61 * *
62 * Utility Functions *
63 * *
64 ****************************************************************************/
65
66 /* Set the trust setting for the root CA in a certificate chain. This is
67 required for the self-test in order to allow signature checks for chains
68 signed by arbitrary CAs to work */
69
setRootTrust(const CRYPT_CERTIFICATE cryptCertChain,BOOLEAN * oldTrustValue,const BOOLEAN newTrustValue)70 int setRootTrust( const CRYPT_CERTIFICATE cryptCertChain,
71 BOOLEAN *oldTrustValue, const BOOLEAN newTrustValue )
72 {
73 int status;
74
75 status = cryptSetAttribute( cryptCertChain,
76 CRYPT_CERTINFO_CURRENT_CERTIFICATE,
77 CRYPT_CURSOR_LAST );
78 if( cryptStatusError( status ) )
79 return( status );
80 if( oldTrustValue != NULL )
81 {
82 status = cryptGetAttribute( cryptCertChain,
83 CRYPT_CERTINFO_TRUSTED_IMPLICIT,
84 oldTrustValue );
85 if( cryptStatusError( status ) )
86 return( status );
87 }
88 return( cryptSetAttribute( cryptCertChain,
89 CRYPT_CERTINFO_TRUSTED_IMPLICIT,
90 newTrustValue ) );
91 }
92
93 /* Export a certificate in a given format and make sure that the resulting
94 size is consistent with the calculated size */
95
checkExportCert(const CRYPT_CERTIFICATE cryptCert,const BOOLEAN isCertChain,const CRYPT_CERTFORMAT_TYPE format,const C_STR formatDescription)96 static int checkExportCert( const CRYPT_CERTIFICATE cryptCert,
97 const BOOLEAN isCertChain,
98 const CRYPT_CERTFORMAT_TYPE format,
99 const C_STR formatDescription )
100 {
101 BYTE buffer[ 4096 ];
102 int size, status;
103
104 status = cryptExportCert( NULL, 0, &size, format, cryptCert );
105 if( cryptStatusOK( status ) )
106 status = cryptExportCert( buffer, size, &size, format, cryptCert );
107 if( cryptStatusError( status ) )
108 {
109 fprintf( outputStream, "Certificate%s export in %s format failed\n "
110 "with status %d, line %d.\n", isCertChain ? " chain" : "",
111 formatDescription, status, __LINE__ );
112 return( FALSE );
113 }
114
115 return( TRUE );
116 }
117
118 /****************************************************************************
119 * *
120 * Certificate Creation Routines Test *
121 * *
122 ****************************************************************************/
123
124 BYTE FAR_BSS certBuffer[ BUFFER_SIZE ];
125 int certificateLength;
126
127 /* Create a series of self-signed certs */
128
129 static const CERT_DATA FAR_BSS certData[] = {
130 /* Identification information */
131 { CRYPT_CERTINFO_COUNTRYNAME, IS_STRING, 0, TEXT( "NZ" ) },
132 { CRYPT_CERTINFO_ORGANIZATIONNAME, IS_STRING, 0, TEXT( "Dave's Wetaburgers" ) },
133 { CRYPT_CERTINFO_ORGANIZATIONALUNITNAME, IS_STRING, 0, TEXT( "Procurement" ) },
134 { CRYPT_CERTINFO_COMMONNAME, IS_STRING, 0, TEXT( "Dave Smith" ) },
135
136 /* Self-signed X.509v3 certificate (technically it'd be an X.509v1, but
137 cryptlib automatically adds some required standard attributes so it
138 becomes an X.509v3 certificate) */
139 { CRYPT_CERTINFO_SELFSIGNED, IS_NUMERIC, TRUE },
140
141 { CRYPT_ATTRIBUTE_NONE, IS_VOID }
142 };
143
testBasicCert(void)144 int testBasicCert( void )
145 {
146 CRYPT_CERTIFICATE cryptCert;
147 CRYPT_CONTEXT pubKeyContext, privKeyContext;
148 int value, status;
149
150 #if defined( _MSC_VER ) && ( _MSC_VER <= 800 )
151 time_t testTime = time( NULL ), newTime;
152
153 newTime = mktime( localtime( &testTime ) );
154 if( newTime == testTime )
155 {
156 puts( "Illogical local/GMT time detected. VC++ 1.5x occasionally "
157 "exhibits a bug in\nits time zone handling in which it thinks "
158 "that the local time zone is GMT and\nGMT itself is some "
159 "negative offset from the current time. This upsets\n"
160 "cryptlibs certificate date validity checking, since "
161 "certificates appear to\nhave inconsistent dates. Deleting "
162 "all the temporary files and rebuilding\ncryptlib after "
163 "restarting your machine may fix this.\n" );
164 return( FALSE );
165 }
166 #endif /* VC++ 1.5 bug check */
167
168 fputs( "Testing certificate creation/export...\n", outputStream );
169
170 /* Create the RSA en/decryption contexts */
171 if( !loadRSAContexts( CRYPT_UNUSED, &pubKeyContext, &privKeyContext ) )
172 return( FALSE );
173
174 /* Create the certificate */
175 status = cryptCreateCert( &cryptCert, CRYPT_UNUSED,
176 CRYPT_CERTTYPE_CERTIFICATE );
177 if( cryptStatusError( status ) )
178 {
179 fprintf( outputStream, "cryptCreateCert() failed with error "
180 "code %d, line %d.\n", status, __LINE__ );
181 return( FALSE );
182 }
183
184 /* Add some certificate components */
185 status = cryptSetAttribute( cryptCert,
186 CRYPT_CERTINFO_SUBJECTPUBLICKEYINFO, pubKeyContext );
187 if( cryptStatusError( status ) )
188 return( attrErrorExit( cryptCert, "cryptSetAttribute()", status,
189 __LINE__ ) );
190 if( !addCertFields( cryptCert, certData, __LINE__ ) )
191 return( FALSE );
192
193 /* Delete a component and replace it with something else */
194 status = cryptDeleteAttribute( cryptCert, CRYPT_CERTINFO_COMMONNAME );
195 if( cryptStatusError( status ) )
196 return( attrErrorExit( cryptCert, "cryptDeleteAttribute()", status,
197 __LINE__ ) );
198 cryptSetAttributeString( cryptCert,
199 CRYPT_CERTINFO_COMMONNAME, TEXT( "Dave Taylor" ),
200 paramStrlen( TEXT( "Dave Taylor" ) ) );
201
202 /* Sign the certificate and print information on what we got */
203 status = cryptSignCert( cryptCert, privKeyContext );
204 if( cryptStatusError( status ) )
205 return( attrErrorExit( cryptCert, "cryptSignCert()", status,
206 __LINE__ ) );
207 destroyContexts( CRYPT_UNUSED, pubKeyContext, privKeyContext );
208 if( !printCertInfo( cryptCert ) )
209 return( FALSE );
210
211 /* Check the signature. Since it's self-signed, we don't need to pass in
212 a signature check key */
213 status = cryptCheckCert( cryptCert, CRYPT_UNUSED );
214 if( cryptStatusError( status ) )
215 return( attrErrorExit( cryptCert, "cryptCheckCert()", status,
216 __LINE__ ) );
217
218 /* Set the certificate usage to untrusted for any purpose, which should
219 result in the signature check failing */
220 cryptSetAttribute( cryptCert, CRYPT_CERTINFO_TRUSTED_USAGE,
221 CRYPT_KEYUSAGE_NONE );
222 status = cryptCheckCert( cryptCert, CRYPT_UNUSED );
223 if( cryptStatusOK( status ) )
224 {
225 puts( "Untrusted certificate signature check succeeded, should "
226 "have failed." );
227 return( FALSE );
228 }
229 cryptDeleteAttribute( cryptCert, CRYPT_CERTINFO_TRUSTED_USAGE );
230
231 /* Export the certificate. We perform a length check using a null
232 buffer to make sure that this facility is working as required */
233 status = cryptExportCert( NULL, 0, &value, CRYPT_CERTFORMAT_CERTIFICATE,
234 cryptCert );
235 if( cryptStatusOK( status ) )
236 status = cryptExportCert( certBuffer, BUFFER_SIZE, &certificateLength,
237 CRYPT_CERTFORMAT_CERTIFICATE, cryptCert );
238 if( cryptStatusError( status ) )
239 return( attrErrorExit( cryptCert, "cryptExportCert()", status,
240 __LINE__ ) );
241 if( value != certificateLength )
242 {
243 puts( "Exported certificate size != actual data size." );
244 return( FALSE );
245 }
246 fprintf( outputStream, "Exported certificate is %d bytes long.\n",
247 certificateLength );
248 debugDump( "cert", certBuffer, certificateLength );
249
250 /* Export the chain in the various text formats to make sure that each
251 one works correctly */
252 if( !checkExportCert( cryptCert, FALSE,
253 CRYPT_CERTFORMAT_TEXT_CERTIFICATE,
254 "CRYPT_CERTFORMAT_TEXT_CERTIFICATE" ) )
255 return( FALSE );
256 if( !checkExportCert( cryptCert, FALSE,
257 CRYPT_CERTFORMAT_TEXT_CERTCHAIN,
258 "CRYPT_CERTFORMAT_TEXT_CERTCHAIN" ) )
259 return( FALSE );
260 if( !checkExportCert( cryptCert, FALSE,
261 CRYPT_CERTFORMAT_XML_CERTIFICATE,
262 "CRYPT_CERTFORMAT_XML_CERTIFICATE" ) )
263 return( FALSE );
264 if( !checkExportCert( cryptCert, FALSE,
265 CRYPT_CERTFORMAT_XML_CERTCHAIN,
266 "CRYPT_CERTFORMAT_XML_CERTCHAIN" ) )
267 return( FALSE );
268
269 /* Destroy the certificate */
270 status = cryptDestroyCert( cryptCert );
271 if( cryptStatusError( status ) )
272 {
273 printf( "cryptDestroyCert() failed with error code %d, line %d.\n",
274 status, __LINE__ );
275 return( FALSE );
276 }
277
278 /* Make sure that we can read what we created */
279 status = cryptImportCert( certBuffer, certificateLength, CRYPT_UNUSED,
280 &cryptCert );
281 if( cryptStatusError( status ) )
282 {
283 fprintf( outputStream, "cryptImportCert() failed with error "
284 "code %d, line %d.\n", status, __LINE__ );
285 return( FALSE );
286 }
287 status = cryptCheckCert( cryptCert, CRYPT_UNUSED );
288 if( cryptStatusError( status ) )
289 {
290 int errorType, errorLocus;
291
292 attrErrorExit( cryptCert, "cryptCheckCert()", status, __LINE__ );
293 status = cryptGetAttribute( cryptCert, CRYPT_ATTRIBUTE_ERRORTYPE,
294 &errorType );
295 if( cryptStatusOK( status ) )
296 {
297 status = cryptGetAttribute( cryptCert,
298 CRYPT_ATTRIBUTE_ERRORLOCUS,
299 &errorLocus );
300 }
301 if( cryptStatusOK( status ) && \
302 errorType == CRYPT_ERRTYPE_CONSTRAINT && \
303 errorLocus == CRYPT_CERTINFO_VALIDFROM )
304 {
305 puts( " (If this test was run within +/- 12 hours of a "
306 "daylight savings time (DST)\n switchover then this is "
307 "a false positive caused by problems in\n performing "
308 "date calculations using the C standard libraries on days "
309 "that\n have 23 or 25 hours due to hours missing or "
310 "being repeated. This problem\n will correct itself "
311 "once the time is more than 12 hours away from the DST\n"
312 " switchover, and only affects the certificate-creation "
313 "self-test)." );
314 }
315
316 return( FALSE );
317 }
318 cryptDestroyCert( cryptCert );
319
320 /* Clean up */
321 fputs( "Certificate creation succeeded.\n\n", outputStream );
322 return( TRUE );
323 }
324
325 static const CERT_DATA FAR_BSS cACertData[] = {
326 /* Identification information. Note the non-heirarchical order of the
327 components to test the automatic arranging of the DN */
328 { CRYPT_CERTINFO_ORGANIZATIONNAME, IS_STRING, 0, TEXT( "Dave's Wetaburgers and CA" ) },
329 { CRYPT_CERTINFO_COMMONNAME, IS_STRING, 0, TEXT( "Dave Himself" ) },
330 { CRYPT_CERTINFO_ORGANIZATIONALUNITNAME, IS_STRING, 0, TEXT( "Certification Division" ) },
331 { CRYPT_CERTINFO_COUNTRYNAME, IS_STRING, 0, TEXT( "NZ" ) },
332
333 /* Self-signed X.509v3 certificate */
334 { CRYPT_CERTINFO_SELFSIGNED, IS_NUMERIC, TRUE },
335
336 /* Start date set to a fixed value to check for problems in date/time
337 conversion routines, expiry date set to > Y2K to test for Y2K
338 problems. In theory the start time should be set to < Y2K to
339 properly test the time handling, however the kernel won't allow
340 times backdated this far so we have to set the value to the minimum
341 allowed by the kernel, which is well after Y2K */
342 { CRYPT_CERTINFO_VALIDFROM, IS_TIME, 0, NULL, CERTTIME_DATETEST },
343 { CRYPT_CERTINFO_VALIDTO, IS_TIME, 0, NULL, CERTTIME_Y2KTEST },
344
345 /* CA extensions. Policies are very much CA-specific and currently
346 undefined, so we use a dummy OID for a nonexistant private org for
347 now */
348 { CRYPT_CERTINFO_KEYUSAGE, IS_NUMERIC,
349 CRYPT_KEYUSAGE_KEYCERTSIGN | CRYPT_KEYUSAGE_CRLSIGN },
350 { CRYPT_CERTINFO_CA, IS_NUMERIC, TRUE },
351 { CRYPT_CERTINFO_PATHLENCONSTRAINT, IS_NUMERIC, 0 },
352 { CRYPT_CERTINFO_CERTPOLICYID, IS_STRING, 0, TEXT( "1 3 6 1 4 1 9999 1" ) },
353 /* Blank line needed due to bug in Borland C++ parser */
354 { CRYPT_CERTINFO_CERTPOLICY_EXPLICITTEXT, IS_STRING, 0, TEXT( "This policy isn't worth the paper it's not printed on." ) },
355 { CRYPT_CERTINFO_CERTPOLICY_ORGANIZATION, IS_STRING, 0, TEXT( "Honest Joe's used cars and certification authority" ) },
356 { CRYPT_CERTINFO_CERTPOLICY_NOTICENUMBERS, IS_NUMERIC, 1 },
357
358 { CRYPT_ATTRIBUTE_NONE, IS_VOID }
359 };
360
testCACert(void)361 int testCACert( void )
362 {
363 CRYPT_CERTIFICATE cryptCert;
364 CRYPT_CONTEXT pubKeyContext, privKeyContext;
365 time_t startTime, endTime DUMMY_INIT;
366 int value, status;
367
368 fputs( "Testing CA certificate creation/export...\n", outputStream );
369
370 /* Create the RSA en/decryption contexts */
371 if( !loadRSAContexts( CRYPT_UNUSED, &pubKeyContext, &privKeyContext ) )
372 return( FALSE );
373
374 /* Create the certificate */
375 status = cryptCreateCert( &cryptCert, CRYPT_UNUSED,
376 CRYPT_CERTTYPE_CERTIFICATE );
377 if( cryptStatusError( status ) )
378 {
379 fprintf( outputStream, "cryptCreateCert() failed with error "
380 "code %d, line %d.\n", status, __LINE__ );
381 return( FALSE );
382 }
383
384 /* Test the ability to handle conversion of 32 <-> 64-bit time_t
385 values in Win32 (but not Win64, where they're always 64-bit) */
386 #if defined( __WINDOWS__ ) && defined( _WIN32 ) && defined( _MSC_VER ) && \
387 !defined( _M_X64 )
388 {
389 const __int64 time64 = CERTTIME_DATETEST;
390 const unsigned int time32 = CERTTIME_DATETEST;
391
392 status = cryptSetAttributeString( cryptCert, CRYPT_CERTINFO_VALIDFROM,
393 &time64, sizeof( time64 ) );
394 if( cryptStatusOK( status ) )
395 {
396 cryptDeleteAttribute( cryptCert, CRYPT_CERTINFO_VALIDFROM );
397 status = cryptSetAttributeString( cryptCert, CRYPT_CERTINFO_VALIDFROM,
398 &time32, sizeof( time32 ) );
399 cryptDeleteAttribute( cryptCert, CRYPT_CERTINFO_VALIDFROM );
400 }
401 if( cryptStatusError( status ) )
402 {
403 printf( "Automatic 64 <-> 32-bit time_t correction failed, "
404 "line %d.\n", __LINE__ );
405 return( FALSE );
406 }
407 }
408 #endif /* Win32 with VC++ */
409
410 /* Add some certificate components */
411 status = cryptSetAttribute( cryptCert,
412 CRYPT_CERTINFO_SUBJECTPUBLICKEYINFO, pubKeyContext );
413 if( cryptStatusError( status ) )
414 return( attrErrorExit( cryptCert, "cryptSetAttribute()", status,
415 __LINE__ ) );
416 if( !addCertFields( cryptCert, cACertData, __LINE__ ) )
417 return( FALSE );
418
419 /* Sign the certificate and print information on what we got */
420 status = cryptSignCert( cryptCert, privKeyContext );
421 if( cryptStatusError( status ) )
422 return( attrErrorExit( cryptCert, "cryptSignCert()", status,
423 __LINE__ ) );
424 destroyContexts( CRYPT_UNUSED, pubKeyContext, privKeyContext );
425 if( !printCertInfo( cryptCert ) )
426 return( FALSE );
427
428 /* Export the certificate, this time with base64 encoding to make sure
429 that this works. As before, we perform a length check using a null
430 buffer to make sure that this facility is working as required */
431 status = cryptExportCert( NULL, 0, &value,
432 CRYPT_CERTFORMAT_TEXT_CERTIFICATE, cryptCert );
433 if( cryptStatusOK( status ) )
434 status = cryptExportCert( certBuffer, BUFFER_SIZE, &certificateLength,
435 CRYPT_CERTFORMAT_TEXT_CERTIFICATE, cryptCert );
436 if( cryptStatusError( status ) )
437 return( attrErrorExit( cryptCert, "cryptExportCert()", status,
438 __LINE__ ) );
439 if( value != certificateLength )
440 {
441 puts( "Exported certificate size != actual data size." );
442 return( FALSE );
443 }
444 fprintf( outputStream, "Exported certificate is %d bytes long.\n",
445 certificateLength );
446 debugDump( "cacert", certBuffer, certificateLength );
447
448 /* Destroy the certificate */
449 status = cryptDestroyCert( cryptCert );
450 if( cryptStatusError( status ) )
451 {
452 printf( "cryptDestroyCert() failed with error code %d, line %d.\n",
453 status, __LINE__ );
454 return( FALSE );
455 }
456
457 /* Make sure that we can read what we created. We make the second
458 parameter to the check function the certificate (rather than
459 CRYPT_UNUSED as done for the basic self-signed certificate) to check
460 that this option works as required, and then retry with CRYPT_UNUSED
461 to check the other possibility (although it's already been checked in
462 the basic certificate above) */
463 status = cryptImportCert( certBuffer, certificateLength, CRYPT_UNUSED,
464 &cryptCert );
465 if( cryptStatusError( status ) )
466 {
467 fprintf( outputStream, "cryptImportCert() failed with error "
468 "code %d, line %d.\n", status, __LINE__ );
469 return( FALSE );
470 }
471 status = cryptCheckCert( cryptCert, cryptCert );
472 if( cryptStatusOK( status ) )
473 status = cryptCheckCert( cryptCert, CRYPT_UNUSED );
474 if( cryptStatusError( status ) )
475 return( attrErrorExit( cryptCert, "cryptCheckCert()", status,
476 __LINE__ ) );
477 status = cryptGetAttributeString( cryptCert, CRYPT_CERTINFO_VALIDFROM,
478 &startTime, &value );
479 if( cryptStatusOK( status ) )
480 status = cryptGetAttributeString( cryptCert, CRYPT_CERTINFO_VALIDTO,
481 &endTime, &value );
482 if( cryptStatusError( status ) )
483 {
484 printf( "Certificate time read failed with error code %d, line "
485 "%d.\n", status, __LINE__ );
486 return( FALSE );
487 }
488 if( startTime != CERTTIME_DATETEST )
489 {
490 printf( "Warning: Certificate start time is wrong, got "
491 TIMET_FORMAT ", should be %lX.\n This is probably "
492 "due to problems in the system time handling routines.\n",
493 startTime, CERTTIME_DATETEST );
494 }
495 if( endTime != CERTTIME_Y2KTEST )
496 {
497 printf( "Warning: Certificate end time is wrong, got " TIMET_FORMAT
498 ", should be %lX.\n This is probably due to "
499 "problems in the system time handling routines.\n",
500 endTime, CERTTIME_Y2KTEST );
501 }
502 cryptDestroyCert( cryptCert );
503 #if defined( __WINDOWS__ ) || defined( __linux__ ) || defined( sun )
504 if( ( startTime != CERTTIME_DATETEST && \
505 ( startTime - CERTTIME_DATETEST != 3600 && \
506 startTime - CERTTIME_DATETEST != -3600 ) ) || \
507 ( endTime != CERTTIME_Y2KTEST && \
508 ( endTime - CERTTIME_Y2KTEST != 3600 && \
509 endTime - CERTTIME_Y2KTEST != -3600 ) ) )
510 {
511 /* If the time is off by exactly one hour this isn't a problem
512 because the best we can do is get the time adjusted for DST
513 now rather than DST when the certificate was created, a problem
514 that is more or less undecidable. In addition we don't
515 automatically abort for arbitrary systems since date problems
516 usually arise from incorrectly configured time zone info or bugs
517 in the system date-handling routines or who knows what, aborting
518 on every random broken system would lead to a flood of
519 unnecessary "bug" reports */
520 return( FALSE );
521 }
522 #endif /* System with known-good time handling */
523
524 /* Clean up */
525 fputs( "CA certificate creation succeeded.\n\n", outputStream );
526 return( TRUE );
527 }
528
529 static const CERT_DATA FAR_BSS xyzzyCertData[] = {
530 /* Identification information */
531 { CRYPT_CERTINFO_COMMONNAME, IS_STRING, 0, TEXT( "Dave Smith" ) },
532
533 /* XYZZY certificate */
534 { CRYPT_CERTINFO_XYZZY, IS_NUMERIC, TRUE },
535
536 { CRYPT_ATTRIBUTE_NONE, IS_VOID }
537 };
538
xyzzyCert(const BOOLEAN useAltAlgo)539 static int xyzzyCert( const BOOLEAN useAltAlgo )
540 {
541 CRYPT_CERTIFICATE cryptCert;
542 CRYPT_CONTEXT pubKeyContext, privKeyContext;
543 int status;
544
545 fprintf( outputStream, "Testing %sXYZZY certificate creation/export...\n",
546 useAltAlgo ? "DSA " : "" );
547
548 /* Create the RSA en/decryption contexts */
549 if( useAltAlgo )
550 {
551 if( !loadDSAContexts( CRYPT_UNUSED, &pubKeyContext, &privKeyContext ) )
552 return( FALSE );
553 }
554 else
555 {
556 if( !loadRSAContexts( CRYPT_UNUSED, &pubKeyContext, &privKeyContext ) )
557 return( FALSE );
558 }
559
560 /* Create the certificate */
561 status = cryptCreateCert( &cryptCert, CRYPT_UNUSED,
562 CRYPT_CERTTYPE_CERTIFICATE );
563 if( cryptStatusError( status ) )
564 {
565 fprintf( outputStream, "cryptCreateCert() failed with error "
566 "code %d, line %d.\n", status, __LINE__ );
567 return( FALSE );
568 }
569
570 /* Add some certificate components */
571 status = cryptSetAttribute( cryptCert,
572 CRYPT_CERTINFO_SUBJECTPUBLICKEYINFO, pubKeyContext );
573 if( cryptStatusError( status ) )
574 return( attrErrorExit( cryptCert, "cryptSetAttribute()", status,
575 __LINE__ ) );
576 if( !addCertFields( cryptCert, xyzzyCertData, __LINE__ ) )
577 return( FALSE );
578
579 /* Sign the certificate and print information on what we got */
580 status = cryptSignCert( cryptCert, privKeyContext );
581 if( cryptStatusError( status ) )
582 return( attrErrorExit( cryptCert, "cryptSignCert()", status,
583 __LINE__ ) );
584 destroyContexts( CRYPT_UNUSED, pubKeyContext, privKeyContext );
585 if( !printCertInfo( cryptCert ) )
586 return( FALSE );
587
588 /* Check the signature. Since it's self-signed, we don't need to pass in
589 a signature check key */
590 status = cryptCheckCert( cryptCert, CRYPT_UNUSED );
591 if( cryptStatusError( status ) )
592 return( attrErrorExit( cryptCert, "cryptCheckCert()", status,
593 __LINE__ ) );
594
595 /* Export the certificate */
596 status = cryptExportCert( certBuffer, BUFFER_SIZE, &certificateLength,
597 CRYPT_CERTFORMAT_CERTIFICATE, cryptCert );
598 if( cryptStatusError( status ) )
599 return( attrErrorExit( cryptCert, "cryptExportCert()", status,
600 __LINE__ ) );
601 fprintf( outputStream, "Exported certificate is %d bytes long.\n",
602 certificateLength );
603 debugDump( useAltAlgo ? "certxyd" : "certxy", certBuffer,
604 certificateLength );
605
606 /* Destroy the certificate */
607 status = cryptDestroyCert( cryptCert );
608 if( cryptStatusError( status ) )
609 {
610 printf( "cryptDestroyCert() failed with error code %d, line %d.\n",
611 status, __LINE__ );
612 return( FALSE );
613 }
614
615 /* Make sure that we can read what we created */
616 status = cryptImportCert( certBuffer, certificateLength, CRYPT_UNUSED,
617 &cryptCert );
618 if( cryptStatusError( status ) )
619 {
620 fprintf( outputStream, "cryptImportCert() failed with error "
621 "code %d, line %d.\n", status, __LINE__ );
622 return( FALSE );
623 }
624 status = cryptCheckCert( cryptCert, CRYPT_UNUSED );
625 if( cryptStatusError( status ) )
626 return( attrErrorExit( cryptCert, "cryptCheckCert()", status,
627 __LINE__ ) );
628 cryptDestroyCert( cryptCert );
629
630 /* Clean up */
631 fprintf( outputStream, "%sXYZZY certificate creation succeeded.\n\n",
632 useAltAlgo ? "DSA " : "" );
633 return( TRUE );
634 }
635
testXyzzyCert(void)636 int testXyzzyCert( void )
637 {
638 if( !xyzzyCert( FALSE ) )
639 return( FALSE );
640 return( xyzzyCert( TRUE ) );
641 }
642
643 #ifdef HAS_WIDECHAR
644
645 static const wchar_t FAR_BSS unicodeStr[] = {
646 0x0414, 0x043E, 0x0432, 0x0435, 0x0440, 0x044F, 0x0439, 0x002C,
647 0x0020, 0x043D, 0x043E, 0x0020, 0x043F, 0x0440, 0x043E, 0x0432,
648 0x0435, 0x0440, 0x044F, 0x0439, 0x0000 };
649 static const wchar_t FAR_BSS unicode2Str[] = {
650 0x004D, 0x0061, 0x0072, 0x0074, 0x0069, 0x006E, 0x0061, 0x0020,
651 0x0160, 0x0069, 0x006B, 0x006F, 0x0076, 0x006E, 0x00E1, 0x0000 };
652 #ifdef __UNIX__ /* Only enabled for native-UTF8 environments */
653 static const BYTE FAR_BSS utf8OriginalStr[] = {
654 0xC3, 0x98, 0xC3, 0x86, 0xC3, 0x85, 0xC3, 0xA6, 0xC3, 0xB8, 0xC3,
655 0xA5, 0x00 };
656 static const BYTE FAR_BSS utf8EncodedStr[] = {
657 0xC3, 0x83, 0xCB, 0x9C, 0xC3, 0x83, 0xE2, 0x80, 0xA0, 0xC3, 0x83,
658 0xE2, 0x80, 0xA6, 0xC3, 0x83, 0xC2, 0xA6, 0xC3, 0x83, 0xC2, 0xB8,
659 0xC3, 0x83, 0xC2, 0xA5, 0x00 };
660 #endif /* __UNIX__ */
661
662 static const CERT_DATA FAR_BSS textStringCertData[] = {
663 /* Identification information: A latin-1 string, an obviously Unicode
664 string, a less-obviously Unicode string (only the 0x160 value is
665 larger than 8 bits), an ASCII-in-Unicode string, and an ASCII
666 string */
667 { CRYPT_CERTINFO_COMMONNAME, IS_STRING, 0, TEXT( "H�rr �sterix" ) },
668 { CRYPT_CERTINFO_ORGANIZATIONALUNITNAME, IS_WCSTRING, 0, unicodeStr },
669 { CRYPT_CERTINFO_LOCALITYNAME, IS_WCSTRING, 0, unicode2Str },
670 { CRYPT_CERTINFO_ORGANIZATIONNAME, IS_WCSTRING, 0, L"Dave's Unicode-aware CA with very long string" },
671 #ifdef __UNIX__
672 { CRYPT_CERTINFO_STATEORPROVINCENAME, IS_STRING, 0, utf8EncodedStr },
673 #endif /* __UNIX__ */
674 { CRYPT_CERTINFO_COUNTRYNAME, IS_STRING, 0, TEXT( "GB" ) },
675
676 /* Another XYZZY certificate */
677 { CRYPT_CERTINFO_XYZZY, IS_NUMERIC, TRUE },
678
679 { CRYPT_ATTRIBUTE_NONE, IS_VOID }
680 };
681
testTextStringCert(void)682 int testTextStringCert( void )
683 {
684 CRYPT_CERTIFICATE cryptCert;
685 CRYPT_CONTEXT pubKeyContext, privKeyContext;
686 int i, status;
687
688 fputs( "Testing complex string type certificate creation/export...\n",
689 outputStream );
690
691 /* Create the RSA en/decryption contexts */
692 if( !loadRSAContexts( CRYPT_UNUSED, &pubKeyContext, &privKeyContext ) )
693 return( FALSE );
694
695 /* Create the certificate */
696 status = cryptCreateCert( &cryptCert, CRYPT_UNUSED,
697 CRYPT_CERTTYPE_CERTIFICATE );
698 if( cryptStatusError( status ) )
699 {
700 fprintf( outputStream, "cryptCreateCert() failed with error "
701 "code %d, line %d.\n", status, __LINE__ );
702 return( FALSE );
703 }
704
705 /* Add some certificate components */
706 status = cryptSetAttribute( cryptCert,
707 CRYPT_CERTINFO_SUBJECTPUBLICKEYINFO, pubKeyContext );
708 if( cryptStatusError( status ) )
709 return( attrErrorExit( cryptCert, "cryptSetAttribute()", status,
710 __LINE__ ) );
711 if( !addCertFields( cryptCert, textStringCertData, __LINE__ ) )
712 return( FALSE );
713
714 /* Sign the certificate and print information on what we got */
715 status = cryptSignCert( cryptCert, privKeyContext );
716 if( cryptStatusError( status ) )
717 return( attrErrorExit( cryptCert, "cryptSignCert()", status,
718 __LINE__ ) );
719 destroyContexts( CRYPT_UNUSED, pubKeyContext, privKeyContext );
720 if( !printCertInfo( cryptCert ) )
721 return( FALSE );
722
723 /* Check the signature. Since it's self-signed, we don't need to pass in
724 a signature check key */
725 status = cryptCheckCert( cryptCert, CRYPT_UNUSED );
726 if( cryptStatusError( status ) )
727 return( attrErrorExit( cryptCert, "cryptCheckCert()", status,
728 __LINE__ ) );
729
730 /* Export the certificate */
731 status = cryptExportCert( certBuffer, BUFFER_SIZE, &certificateLength,
732 CRYPT_CERTFORMAT_CERTIFICATE, cryptCert );
733 if( cryptStatusError( status ) )
734 return( attrErrorExit( cryptCert, "cryptExportCert()", status,
735 __LINE__ ) );
736 fprintf( outputStream, "Exported certificate is %d bytes long.\n",
737 certificateLength );
738 debugDump( "certstr", certBuffer, certificateLength );
739
740 /* Destroy the certificate */
741 status = cryptDestroyCert( cryptCert );
742 if( cryptStatusError( status ) )
743 {
744 printf( "cryptDestroyCert() failed with error code %d, line %d.\n",
745 status, __LINE__ );
746 return( FALSE );
747 }
748
749 /* Make sure that we can read what we created */
750 status = cryptImportCert( certBuffer, certificateLength, CRYPT_UNUSED,
751 &cryptCert );
752 if( cryptStatusError( status ) )
753 {
754 fprintf( outputStream, "cryptImportCert() failed with error "
755 "code %d, line %d.\n", status, __LINE__ );
756 return( FALSE );
757 }
758 status = cryptCheckCert( cryptCert, CRYPT_UNUSED );
759 if( cryptStatusError( status ) )
760 return( attrErrorExit( cryptCert, "cryptCheckCert()", status,
761 __LINE__ ) );
762
763 /* Make sure that we can read back what we've written and that it was
764 correctly converted back to the original string value */
765 for( i = 0; textStringCertData[ i ].type != CRYPT_CERTINFO_XYZZY; i++ )
766 {
767 const CRYPT_ATTRIBUTE_TYPE attribute = textStringCertData[ i ].type;
768 BYTE buffer[ 256 ];
769 int length;
770
771 status = cryptGetAttributeString( cryptCert, attribute, buffer,
772 &length );
773 if( cryptStatusError( status ) )
774 {
775 printf( "Attempt to read back DN value %d failed with error "
776 "code %d, line %d.\n", attribute, status, __LINE__ );
777 return( FALSE );
778 }
779 if( textStringCertData[ i ].componentType == IS_WCSTRING )
780 {
781 #ifdef HAS_WIDECHAR
782 const int wstrLen = wcslen( textStringCertData[ i ].stringValue ) * \
783 sizeof( wchar_t );
784 if( wstrLen != length || \
785 memcmp( buffer, textStringCertData[ i ].stringValue, length ) )
786 {
787 if( attribute == CRYPT_CERTINFO_ORGANIZATIONNAME )
788 {
789 /* This is an ASCII string disguised as Unicode, which
790 cryptlib correctly canonicalises back to ASCII */
791 continue;
792 }
793 printf( "Widechar DN value %d read from certificate with value\n",
794 attribute );
795 printHex( " ", buffer, length );
796 printf( "doesn't match value\n" );
797 printHex( " ", textStringCertData[ i ].stringValue, wstrLen );
798 printf( "that was written, line %d.\n", __LINE__ );
799 return( FALSE );
800 }
801 #endif /* HAS_WIDECHAR */
802 }
803 else
804 {
805 const int strLen = paramStrlen( textStringCertData[ i ].stringValue );
806 if( strLen != length || \
807 memcmp( buffer, textStringCertData[ i ].stringValue, length ) )
808 {
809 if( attribute == CRYPT_CERTINFO_STATEORPROVINCENAME )
810 {
811 /* This is a UTF8 string that cryptlib canonicalises into
812 Unicode (since there's no way to tell what the host
813 system uses as its native 8-bit character system) so
814 the encoded form as read doesn't match what's
815 written */
816 continue;
817 }
818 printf( "DN value %d read from certificate with value\n",
819 attribute );
820 printHex( " ", buffer, length );
821 printf( "doesn't match value\n" );
822 printHex( " ", textStringCertData[ i ].stringValue, strLen );
823 printf( "that was written, line %d.\n", __LINE__ );
824 return( FALSE );
825 }
826 }
827 }
828 cryptDestroyCert( cryptCert );
829
830 /* Clean up */
831 fputs( "Complex string type certificate creation succeeded.\n\n",
832 outputStream );
833 return( TRUE );
834 }
835 #else
836
testTextStringCert(void)837 int testTextStringCert( void )
838 {
839 return( TRUE );
840 }
841 #endif /* Unicode-aware systems */
842
843 static const CERT_DATA FAR_BSS complexCertData[] = {
844 /* Identification information */
845 { CRYPT_CERTINFO_COUNTRYNAME, IS_STRING, 0, TEXT( "US" ) },
846 { CRYPT_CERTINFO_ORGANIZATIONNAME, IS_STRING, 0, TEXT( "Dave's Wetaburgers and Netscape CA" ) },
847 { CRYPT_CERTINFO_ORGANIZATIONALUNITNAME, IS_STRING, 0, TEXT( "SSL Certificates" ) },
848 { CRYPT_CERTINFO_COMMONNAME, IS_STRING, 0, TEXT( "Robert';DROP TABLE certificates;--" ) },
849
850 /* Self-signed X.509v3 certificate */
851 { CRYPT_CERTINFO_SELFSIGNED, IS_NUMERIC, TRUE },
852
853 /* Subject altName */
854 { CRYPT_CERTINFO_RFC822NAME, IS_STRING, 0, TEXT( "dave@wetas-r-us.com" ) },
855 { CRYPT_CERTINFO_UNIFORMRESOURCEIDENTIFIER, IS_STRING, 0, TEXT( "http://www.wetas-r-us.com" ) },
856
857 /* Oddball altName components. Note that the otherName.value must be a
858 DER-encoded ASN.1 object */
859 { CRYPT_CERTINFO_EDIPARTYNAME_NAMEASSIGNER, IS_STRING, 0, TEXT( "EDI Name Assigner" ) },
860 { CRYPT_CERTINFO_EDIPARTYNAME_PARTYNAME, IS_STRING, 0, TEXT( "EDI Party Name" ) },
861 { CRYPT_CERTINFO_OTHERNAME_TYPEID, IS_STRING, 0, TEXT( "1 3 6 1 4 1 9999 2" ) },
862 { CRYPT_CERTINFO_OTHERNAME_VALUE, IS_STRING, 10, "\x04\x08" "12345678" },
863
864 #ifdef USE_CERTLEVEL_PKIX_FULL
865 /* Path constraint */
866 { CRYPT_ATTRIBUTE_CURRENT, IS_NUMERIC, CRYPT_CERTINFO_EXCLUDEDSUBTREES },
867 { CRYPT_CERTINFO_COUNTRYNAME, IS_STRING, 0, TEXT( "CZ" ) },
868 { CRYPT_CERTINFO_ORGANIZATIONNAME, IS_STRING, 0, TEXT( "Dave's Brother's CA" ) },
869 { CRYPT_CERTINFO_ORGANIZATIONALUNITNAME, IS_STRING, 0, TEXT( "SSL Certificates" ) },
870 #endif /* USE_CERTLEVEL_PKIX_FULL */
871
872 /* CRL distribution points */
873 { CRYPT_ATTRIBUTE_CURRENT, IS_NUMERIC, CRYPT_CERTINFO_CRLDIST_FULLNAME },
874 { CRYPT_CERTINFO_UNIFORMRESOURCEIDENTIFIER, IS_STRING, 0, TEXT( "http://www.revocations.com/crls/" ) },
875
876 /* SubjectInfoAccess */
877 { CRYPT_ATTRIBUTE_CURRENT, IS_NUMERIC, CRYPT_CERTINFO_SUBJECTINFO_CAREPOSITORY },
878 { CRYPT_CERTINFO_UNIFORMRESOURCEIDENTIFIER, IS_STRING, 0, TEXT( "http://192.168.1.1:8080/timesheet.asp?userid=1234;DROP%20TABLE%20USERS" ) },
879
880 #ifdef USE_CERT_OBSOLETE
881 /* Add a vendor-specific extension, in this case a Thawte strong extranet
882 extension */
883 { CRYPT_CERTINFO_STRONGEXTRANET_ZONE, IS_NUMERIC, 0x99 },
884 { CRYPT_CERTINFO_STRONGEXTRANET_ID, IS_STRING, 0, TEXT( "EXTRA1" ) },
885 #endif /* USE_CERT_OBSOLETE */
886
887 #ifdef USE_CERTLEVEL_PKIX_PARTIAL
888 /* Misc funnies */
889 { CRYPT_CERTINFO_OCSP_NOCHECK, IS_NUMERIC, CRYPT_UNUSED },
890 #endif /* USE_CERTLEVEL_PKIX_PARTIAL */
891
892 /* Re-select the subject name after poking around in the altName */
893 { CRYPT_ATTRIBUTE_CURRENT, IS_NUMERIC, CRYPT_CERTINFO_SUBJECTNAME },
894
895 { CRYPT_ATTRIBUTE_NONE, IS_VOID }
896 };
897
testComplexCert(void)898 int testComplexCert( void )
899 {
900 CRYPT_CERTIFICATE cryptCert;
901 CRYPT_CONTEXT pubKeyContext, privKeyContext;
902 C_CHR buffer1[ 64 ], buffer2[ 64 ];
903 int length1 DUMMY_INIT, length2 DUMMY_INIT, status;
904
905 fputs( "Testing complex certificate creation/export...\n",
906 outputStream );
907
908 /* Create the RSA en/decryption contexts */
909 if( !loadRSAContexts( CRYPT_UNUSED, &pubKeyContext, &privKeyContext ) )
910 return( FALSE );
911
912 /* Create the certificate */
913 status = cryptCreateCert( &cryptCert, CRYPT_UNUSED,
914 CRYPT_CERTTYPE_CERTIFICATE );
915 if( cryptStatusError( status ) )
916 {
917 fprintf( outputStream, "cryptCreateCert() failed with error "
918 "code %d, line %d.\n", status, __LINE__ );
919 return( FALSE );
920 }
921
922 /* Add some certificate components */
923 status = cryptSetAttribute( cryptCert,
924 CRYPT_CERTINFO_SUBJECTPUBLICKEYINFO, pubKeyContext );
925 if( cryptStatusError( status ) )
926 return( attrErrorExit( cryptCert, "cryptSetAttribute()", status,
927 __LINE__ ) );
928 if( !addCertFields( cryptCert, complexCertData, __LINE__ ) )
929 return( FALSE );
930
931 /* Add an OID, read it back, and make sure that the OID en/decoding
932 worked correctly */
933 status = cryptSetAttributeString( cryptCert, CRYPT_CERTINFO_CERTPOLICYID,
934 TEXT( "1 2 3 4 5" ),
935 paramStrlen( TEXT( "1 2 3 4 5" ) ) );
936 if( cryptStatusOK( status ) )
937 status = cryptGetAttributeString( cryptCert,
938 CRYPT_CERTINFO_CERTPOLICYID,
939 buffer1, &length1 );
940 if( cryptStatusOK( status ) )
941 status = cryptDeleteAttribute( cryptCert, CRYPT_CERTINFO_CERTPOLICYID );
942 if( cryptStatusOK( status ) && \
943 ( length1 != ( int ) paramStrlen( TEXT( "1 2 3 4 5" ) ) || \
944 memcmp( buffer1, TEXT( "1 2 3 4 5" ), length1 ) ) )
945 {
946 printf( "Error in OID en/decoding, line %d.\n", __LINE__ );
947 return( FALSE );
948 }
949
950 /* Add a non-CA basicConstraint, delete it, and re-add it as CA
951 constraint */
952 status = cryptSetAttribute( cryptCert, CRYPT_CERTINFO_CA, FALSE );
953 if( cryptStatusError( status ) )
954 return( attrErrorExit( cryptCert, "cryptSetAttribute()", status,
955 __LINE__ ) );
956 status = cryptDeleteAttribute( cryptCert,
957 CRYPT_CERTINFO_BASICCONSTRAINTS );
958 if( cryptStatusError( status ) )
959 return( attrErrorExit( cryptCert, "cryptDeleteAttribute()", status,
960 __LINE__ ) );
961 if( cryptStatusOK( status ) )
962 status = cryptSetAttribute( cryptCert, CRYPT_CERTINFO_CA, TRUE );
963 if( cryptStatusError( status ) )
964 return( attrErrorExit( cryptCert, "cryptSetAttribute()", status,
965 __LINE__ ) );
966
967 /* Add a disabled attribute and make sure that it's detected. This can
968 be done in one of two ways, either directly by the kernel with a
969 permission error or by the certificate-processing code with a not-
970 available error if we go in indirectly, for example using the
971 attribute cursor */
972 #ifndef USE_CERT_OBSOLETE
973 status = cryptSetAttribute( cryptCert,
974 CRYPT_CERTINFO_STRONGEXTRANET_ZONE, 1 );
975 if( status != CRYPT_ERROR_PARAM2 )
976 {
977 printf( "Addition of disabled attribute %d wasn't detected, "
978 "line %d.\n", CRYPT_CERTINFO_STRONGEXTRANET_ZONE, __LINE__ );
979 return( FALSE );
980 }
981 #endif /* USE_CERT_OBSOLETE */
982 #ifndef USE_CERTLEVEL_PKIX_FULL
983 status = cryptSetAttribute( cryptCert, CRYPT_ATTRIBUTE_CURRENT,
984 CRYPT_CERTINFO_EXCLUDEDSUBTREES );
985 if( status != CRYPT_ERROR_PARAM3 )
986 {
987 printf( "Indirect addition of disabled attribute %d wasn't "
988 "detected, line %d.\n", CRYPT_CERTINFO_EXCLUDEDSUBTREES,
989 __LINE__ );
990 return( FALSE );
991 }
992 #endif /* USE_CERTLEVEL_PKIX_FULL */
993
994 /* Sign the certificate and print information on what we got */
995 status = cryptSignCert( cryptCert, privKeyContext );
996 if( cryptStatusError( status ) )
997 return( attrErrorExit( cryptCert, "cryptSignCert()", status,
998 __LINE__ ) );
999 destroyContexts( CRYPT_UNUSED, pubKeyContext, privKeyContext );
1000 if( !printCertInfo( cryptCert ) )
1001 return( FALSE );
1002
1003 /* Make sure that GeneralName component selection is working properly */
1004 cryptSetAttribute( cryptCert, CRYPT_ATTRIBUTE_CURRENT,
1005 CRYPT_CERTINFO_SUBJECTALTNAME );
1006 status = cryptGetAttributeString( cryptCert,
1007 CRYPT_CERTINFO_RFC822NAME, buffer1, &length1 );
1008 if( cryptStatusOK( status ) )
1009 status = cryptGetAttributeString( cryptCert,
1010 CRYPT_CERTINFO_RFC822NAME, buffer2, &length2 );
1011 if( cryptStatusError( status ) )
1012 {
1013 printf( "Attempt to read and re-read email address failed, line "
1014 "%d.\n", __LINE__ );
1015 return( FALSE );
1016 }
1017 #ifdef UNICODE_STRINGS
1018 buffer1[ length1 / sizeof( wchar_t ) ] = TEXT( '\0' );
1019 buffer2[ length2 / sizeof( wchar_t ) ] = TEXT( '\0' );
1020 #else
1021 buffer1[ length1 ] = '\0';
1022 buffer2[ length2 ] = '\0';
1023 #endif /* UNICODE_STRINGS */
1024 if( ( length1 != ( int ) paramStrlen( TEXT( "dave@wetas-r-us.com" ) ) ) || \
1025 ( length1 != length2 ) || \
1026 memcmp( buffer1, TEXT( "dave@wetas-r-us.com" ), length1 ) || \
1027 memcmp( buffer2, TEXT( "dave@wetas-r-us.com" ), length2 ) )
1028 {
1029 printf( "Email address on read #1 = '%s',\n read #2 = '%s', should "
1030 "have been '%s', line %d.\n", buffer1, buffer2,
1031 "dave@wetas-r-us.com", __LINE__ );
1032 return( FALSE );
1033 }
1034
1035 /* Export the certificate */
1036 status = cryptExportCert( certBuffer, BUFFER_SIZE, &certificateLength,
1037 CRYPT_CERTFORMAT_CERTIFICATE, cryptCert );
1038 if( cryptStatusError( status ) )
1039 return( attrErrorExit( cryptCert, "cryptExportCert()", status,
1040 __LINE__ ) );
1041 fprintf( outputStream, "Exported certificate is %d bytes long.\n",
1042 certificateLength );
1043 debugDump( "certc", certBuffer, certificateLength );
1044
1045 /* Destroy the certificate */
1046 status = cryptDestroyCert( cryptCert );
1047 if( cryptStatusError( status ) )
1048 {
1049 printf( "cryptDestroyCert() failed with error code %d, line %d.\n",
1050 status, __LINE__ );
1051 return( FALSE );
1052 }
1053
1054 /* Make sure that we can read what we created */
1055 status = cryptImportCert( certBuffer, certificateLength, CRYPT_UNUSED,
1056 &cryptCert );
1057 if( cryptStatusError( status ) )
1058 {
1059 fprintf( outputStream, "cryptImportCert() failed with error "
1060 "code %d, line %d.\n", status, __LINE__ );
1061 return( FALSE );
1062 }
1063 status = cryptCheckCert( cryptCert, CRYPT_UNUSED );
1064 if( cryptStatusError( status ) )
1065 return( attrErrorExit( cryptCert, "cryptCheckCert()", status,
1066 __LINE__ ) );
1067 cryptDestroyCert( cryptCert );
1068
1069 /* Clean up */
1070 fputs( "Complex certificate creation succeeded.\n\n", outputStream );
1071 return( TRUE );
1072 }
1073
testCertExtension(void)1074 int testCertExtension( void )
1075 {
1076 CRYPT_CERTIFICATE cryptCert;
1077 CRYPT_CONTEXT pubKeyContext, privKeyContext;
1078 BYTE buffer[ 16 ];
1079 const char *extensionData = "\x0C\x04Test";
1080 int value, length, status;
1081
1082 fputs( "Testing certificate with nonstd.extension creation/export...\n",
1083 outputStream );
1084
1085 /* Create the RSA en/decryption contexts */
1086 if( !loadRSAContexts( CRYPT_UNUSED, &pubKeyContext, &privKeyContext ) )
1087 return( FALSE );
1088
1089 /* Create the certificate */
1090 status = cryptCreateCert( &cryptCert, CRYPT_UNUSED,
1091 CRYPT_CERTTYPE_CERTIFICATE );
1092 if( cryptStatusError( status ) )
1093 {
1094 fprintf( outputStream, "cryptCreateCert() failed with error "
1095 "code %d, line %d.\n", status, __LINE__ );
1096 return( FALSE );
1097 }
1098 status = cryptSetAttribute( cryptCert,
1099 CRYPT_CERTINFO_SUBJECTPUBLICKEYINFO, pubKeyContext );
1100 if( cryptStatusOK( status ) )
1101 status = cryptSetAttribute( cryptCert, CRYPT_CERTINFO_CA, TRUE );
1102 if( cryptStatusError( status ) )
1103 return( attrErrorExit( cryptCert, "cryptSetAttribute()", status,
1104 __LINE__ ) );
1105 if( !addCertFields( cryptCert, certData, __LINE__ ) )
1106 return( FALSE );
1107
1108 /* Add a nonstandard critical extension */
1109 status = cryptAddCertExtension( cryptCert, "1.2.3.4.5", TRUE, extensionData, 6 );
1110 if( cryptStatusError( status ) )
1111 return( attrErrorExit( cryptCert, "cryptAddCertExtension()", status,
1112 __LINE__ ) );
1113
1114 /* Sign the certificate. Since we're adding a nonstandard extension we
1115 have to set the CRYPT_OPTION_CERT_SIGNUNRECOGNISEDATTRIBUTES flag to
1116 make sure that cryptlib will sign it */
1117 status = cryptGetAttribute( CRYPT_UNUSED,
1118 CRYPT_OPTION_CERT_SIGNUNRECOGNISEDATTRIBUTES,
1119 &value );
1120 if( cryptStatusError( status ) )
1121 return( FALSE );
1122 cryptSetAttribute( CRYPT_UNUSED,
1123 CRYPT_OPTION_CERT_SIGNUNRECOGNISEDATTRIBUTES, TRUE );
1124 status = cryptSignCert( cryptCert, privKeyContext );
1125 cryptSetAttribute( CRYPT_UNUSED,
1126 CRYPT_OPTION_CERT_SIGNUNRECOGNISEDATTRIBUTES, value );
1127 if( cryptStatusError( status ) )
1128 return( attrErrorExit( cryptCert, "cryptSignCert()", status,
1129 __LINE__ ) );
1130 destroyContexts( CRYPT_UNUSED, pubKeyContext, privKeyContext );
1131
1132 /* Print information on what we've got */
1133 if( !printCertInfo( cryptCert ) )
1134 return( FALSE );
1135
1136 /* Export the certificate and make sure that we can read what we
1137 created */
1138 status = cryptExportCert( certBuffer, BUFFER_SIZE, &certificateLength,
1139 CRYPT_CERTFORMAT_CERTIFICATE, cryptCert );
1140 if( cryptStatusError( status ) )
1141 return( attrErrorExit( cryptCert, "cryptExportCert()", status,
1142 __LINE__ ) );
1143 fprintf( outputStream, "Exported certificate is %d bytes long.\n",
1144 certificateLength );
1145 debugDump( "certext", certBuffer, certificateLength );
1146 cryptDestroyCert( cryptCert );
1147 status = cryptImportCert( certBuffer, certificateLength, CRYPT_UNUSED,
1148 &cryptCert );
1149 if( cryptStatusError( status ) )
1150 {
1151 fprintf( outputStream, "cryptImportCert() failed with error "
1152 "code %d, line %d.\n", status, __LINE__ );
1153 return( FALSE );
1154 }
1155
1156 /* Check the certificate. Since it contains an unrecognised critical
1157 extension it should be rejected, but accepted at a lowered compliance
1158 level */
1159 status = cryptCheckCert( cryptCert, CRYPT_UNUSED );
1160 if( cryptStatusOK( status ) )
1161 {
1162 printf( "Certificate with unrecognised critical extension was "
1163 "accepted when it should\nhave been rejected, line %d.\n",
1164 __LINE__ );
1165 return( FALSE );
1166 }
1167 ( void ) cryptGetAttribute( CRYPT_UNUSED,
1168 CRYPT_OPTION_CERT_COMPLIANCELEVEL, &value );
1169 cryptSetAttribute( CRYPT_UNUSED, CRYPT_OPTION_CERT_COMPLIANCELEVEL,
1170 CRYPT_COMPLIANCELEVEL_REDUCED );
1171 status = cryptCheckCert( cryptCert, CRYPT_UNUSED );
1172 cryptSetAttribute( CRYPT_UNUSED, CRYPT_OPTION_CERT_COMPLIANCELEVEL,
1173 value );
1174 if( cryptStatusError( status ) )
1175 return( attrErrorExit( cryptCert, "cryptCheckCert()", status,
1176 __LINE__ ) );
1177
1178 /* Read back the nonstandard extension and make sure that it's what we
1179 originally wrote */
1180 status = cryptGetCertExtension( cryptCert, "1.2.3.4.5", &value, buffer,
1181 16, &length );
1182 if( cryptStatusError( status ) )
1183 return( attrErrorExit( cryptCert, "cryptGetCertExtension()", status,
1184 __LINE__ ) );
1185 if( value != TRUE || length != 6 || memcmp( extensionData, buffer, 6 ) )
1186 {
1187 printf( "Recovered nonstandard extension data differs from what was "
1188 "written, line %d.\n", __LINE__ );
1189 return( FALSE );
1190 }
1191
1192 /* Clean up */
1193 cryptDestroyCert( cryptCert );
1194 fputs( "Certificate with nonstd.extension creation succeeded.\n\n",
1195 outputStream );
1196 return( TRUE );
1197 }
1198
testCustomDNCert(void)1199 int testCustomDNCert( void )
1200 {
1201 #ifdef USE_CERT_DNSTRING
1202 CRYPT_CERTIFICATE cryptCert;
1203 CRYPT_CONTEXT pubKeyContext, privKeyContext;
1204 const C_STR customDN = \
1205 TEXT( "cn=Dave Taylor + sn=12345, ou=Org.Unit 2\\=1, " )
1206 TEXT( "ou=Org.Unit 2, ou=Org.Unit 1, " )
1207 TEXT( "o=Dave's Big Organisation, c=PT" );
1208 const C_STR invalidDnStrings[] = {
1209 TEXT( "abc\x01\x64" ) TEXT( "def" ),/* Invalid chars */
1210 TEXT( "cn=" ), /* No value */
1211 TEXT( "cn=\\" ), /* No escaped char */
1212 TEXT( "c\\n=x" ), /* Escape in type */
1213 TEXT( "cn+x" ), /* Spurious '+' */
1214 TEXT( "cn,x" ), /* Spurious ',' */
1215 TEXT( "cn=z=y" ), /* Spurious '=' */
1216 TEXT( "cn=x," ), /* Spurious ',' */
1217 TEXT( "xyz=x" ), /* Unknown type */
1218 NULL
1219 };
1220 char buffer[ BUFFER_SIZE ];
1221 int length, i, status;
1222
1223 fputs( "Testing certificate with custom DN creation/export...\n",
1224 outputStream );
1225
1226 /* Create the RSA en/decryption contexts */
1227 if( !loadRSAContexts( CRYPT_UNUSED, &pubKeyContext, &privKeyContext ) )
1228 return( FALSE );
1229
1230 /* Create the certificate */
1231 status = cryptCreateCert( &cryptCert, CRYPT_UNUSED,
1232 CRYPT_CERTTYPE_CERTIFICATE );
1233 if( cryptStatusError( status ) )
1234 {
1235 fprintf( outputStream, "cryptCreateCert() failed with error "
1236 "code %d, line %d.\n", status, __LINE__ );
1237 return( FALSE );
1238 }
1239 status = cryptSetAttribute( cryptCert,
1240 CRYPT_CERTINFO_SUBJECTPUBLICKEYINFO, pubKeyContext );
1241 if( cryptStatusOK( status ) )
1242 status = cryptSetAttribute( cryptCert, CRYPT_CERTINFO_CA, TRUE );
1243 if( cryptStatusOK( status ) )
1244 status = cryptSetAttribute( cryptCert, CRYPT_CERTINFO_SELFSIGNED, TRUE );
1245 if( cryptStatusError( status ) )
1246 return( attrErrorExit( cryptCert, "cryptSetAttribute()", status,
1247 __LINE__ ) );
1248
1249 /* Make sure that invalid DN strings are detected */
1250 for( i = 0; invalidDnStrings[ i ] != NULL; i++ )
1251 {
1252 status = cryptSetAttributeString( cryptCert, CRYPT_CERTINFO_DN,
1253 invalidDnStrings[ i ],
1254 paramStrlen( invalidDnStrings[ i ] ) );
1255 if( cryptStatusOK( status ) )
1256 {
1257 printf( "Addition of invalid DN string '%s' wasn't detected, "
1258 "line %d.\n", invalidDnStrings[ i ], __LINE__ );
1259 return( FALSE );
1260 }
1261 }
1262
1263 /* Add the custom DN in string form */
1264 status = cryptSetAttributeString( cryptCert, CRYPT_CERTINFO_DN,
1265 customDN, paramStrlen( customDN ) );
1266 if( cryptStatusError( status ) )
1267 return( attrErrorExit( cryptCert, "cryptSetAttributeString()", status,
1268 __LINE__ ) );
1269
1270 /* Sign the certificate and print information on what we got */
1271 status = cryptSignCert( cryptCert, privKeyContext );
1272 if( cryptStatusError( status ) )
1273 return( attrErrorExit( cryptCert, "cryptSignCert()", status,
1274 __LINE__ ) );
1275 destroyContexts( CRYPT_UNUSED, pubKeyContext, privKeyContext );
1276 if( !printCertInfo( cryptCert ) )
1277 return( FALSE );
1278
1279 /* Export the certificate and make sure that we can read what we
1280 created */
1281 status = cryptExportCert( certBuffer, BUFFER_SIZE, &certificateLength,
1282 CRYPT_CERTFORMAT_CERTIFICATE, cryptCert );
1283 if( cryptStatusError( status ) )
1284 return( attrErrorExit( cryptCert, "cryptExportCert()", status,
1285 __LINE__ ) );
1286 fprintf( outputStream, "Exported certificate is %d bytes long.\n",
1287 certificateLength );
1288 debugDump( "certext", certBuffer, certificateLength );
1289 cryptDestroyCert( cryptCert );
1290 status = cryptImportCert( certBuffer, certificateLength, CRYPT_UNUSED,
1291 &cryptCert );
1292 if( cryptStatusError( status ) )
1293 {
1294 fprintf( outputStream, "cryptImportCert() failed with error "
1295 "code %d, line %d.\n", status, __LINE__ );
1296 return( FALSE );
1297 }
1298 status = cryptCheckCert( cryptCert, CRYPT_UNUSED );
1299 if( cryptStatusError( status ) )
1300 return( attrErrorExit( cryptCert, "cryptCheckCert()", status,
1301 __LINE__ ) );
1302
1303 /* Read back the custom DN and make sure that it's what we originally
1304 wrote */
1305 status = cryptGetAttributeString( cryptCert, CRYPT_CERTINFO_DN,
1306 buffer, &length );
1307 if( cryptStatusError( status ) )
1308 return( attrErrorExit( cryptCert, "cryptGetAttributeString()", status,
1309 __LINE__ ) );
1310 if( length != ( int ) paramStrlen( customDN ) || \
1311 memcmp( customDN, buffer, length ) )
1312 {
1313 printf( "Recovered custom DN differs from what was written, line "
1314 "%d.\n", __LINE__ );
1315 return( FALSE );
1316 }
1317
1318 /* Clean up */
1319 cryptDestroyCert( cryptCert );
1320 fputs( "Certificate with custom DN creation succeeded.\n\n",
1321 outputStream );
1322 #else
1323 fputs( "Skipping custom DN certificate creation/export test because "
1324 "support for\nthis capability has been disabled via the cryptlib "
1325 "config options.\n\n", outputStream );
1326 #endif /* USE_CERT_DNSTRING */
1327 return( TRUE );
1328 }
1329
testCertAttributeHandling(void)1330 int testCertAttributeHandling( void )
1331 {
1332 #ifdef USE_CERT_DNSTRING
1333 CRYPT_CERTIFICATE cryptCert;
1334 CRYPT_CONTEXT pubKeyContext, privKeyContext;
1335 const C_STR customDN = \
1336 TEXT( "cn=Dave Taylor, ou=Org.Unit 3, ou=Org.Unit 2, " )
1337 TEXT( "ou=Org.Unit 1, o=Dave's Big Organisation, c=PT" );
1338 const C_STR email = TEXT( "dave@example.com" );
1339 const char *errorString = "(Generic attribute get/set/select error)";
1340 char buffer[ BUFFER_SIZE ];
1341 int length, value, status;
1342
1343 fputs( "Testing certificate attribute handling...\n", outputStream );
1344
1345 /* Create the RSA en/decryption contexts */
1346 if( !loadRSAContexts( CRYPT_UNUSED, &pubKeyContext, &privKeyContext ) )
1347 return( FALSE );
1348
1349 /* Create the certificate */
1350 status = cryptCreateCert( &cryptCert, CRYPT_UNUSED,
1351 CRYPT_CERTTYPE_CERTIFICATE );
1352 if( cryptStatusError( status ) )
1353 {
1354 fprintf( outputStream, "cryptCreateCert() failed with error "
1355 "code %d, line %d.\n", status, __LINE__ );
1356 return( FALSE );
1357 }
1358 status = cryptSetAttribute( cryptCert,
1359 CRYPT_CERTINFO_SUBJECTPUBLICKEYINFO, pubKeyContext );
1360 if( cryptStatusOK( status ) )
1361 status = cryptSetAttribute( cryptCert, CRYPT_CERTINFO_SELFSIGNED, TRUE );
1362 if( cryptStatusError( status ) )
1363 return( attrErrorExit( cryptCert, "cryptSetAttribute()", status,
1364 __LINE__ ) );
1365
1366 /* Add the custom DN in string form and an altName component */
1367 status = cryptSetAttributeString( cryptCert, CRYPT_CERTINFO_DN,
1368 customDN, paramStrlen( customDN ) );
1369 if( cryptStatusOK( status ) )
1370 status = cryptSetAttributeString( cryptCert, CRYPT_CERTINFO_EMAIL,
1371 email, paramStrlen( email ) );
1372 if( cryptStatusError( status ) )
1373 return( attrErrorExit( cryptCert, "cryptSetAttributeString()", status,
1374 __LINE__ ) );
1375
1376 /* Sign the certificate */
1377 status = cryptSignCert( cryptCert, privKeyContext );
1378 if( cryptStatusError( status ) )
1379 return( attrErrorExit( cryptCert, "cryptSignCert()", status,
1380 __LINE__ ) );
1381 destroyContexts( CRYPT_UNUSED, pubKeyContext, privKeyContext );
1382
1383 /* Make sure that the attribute-manipulation routines work as
1384 intended */
1385 status = cryptSetAttribute( cryptCert, CRYPT_ATTRIBUTE_CURRENT,
1386 CRYPT_CERTINFO_SUBJECTALTNAME );
1387 if( cryptStatusOK( status ) )
1388 {
1389 status = cryptGetAttribute( cryptCert, CRYPT_ATTRIBUTE_CURRENT,
1390 &value );
1391 if( cryptStatusError( status ) || \
1392 value != CRYPT_CERTINFO_SUBJECTALTNAME )
1393 {
1394 errorString = "Current attribute != subject altName after "
1395 "subject altName was selected";
1396 status = -1;
1397 }
1398 }
1399 if( cryptStatusOK( status ) )
1400 {
1401 status = cryptGetAttributeString( cryptCert, CRYPT_CERTINFO_EMAIL,
1402 buffer, &length );
1403 if( cryptStatusError( status ) )
1404 errorString = "Fetch of email address from altName failed";
1405 }
1406 if( cryptStatusOK( status ) )
1407 {
1408 /* Should fail since we've now selected the DN in the altName */
1409 status = cryptGetAttributeString( cryptCert,
1410 CRYPT_CERTINFO_ORGANISATIONALUNITNAME,
1411 buffer, &length );
1412 if( cryptStatusOK( status ) )
1413 {
1414 errorString = "OU was returned after altName was selected";
1415 status = -1;
1416 }
1417 else
1418 status = CRYPT_OK;
1419 }
1420 if( cryptStatusError( status ) )
1421 {
1422 printf( "%s, line %d.\n", errorString, __LINE__ );
1423 return( FALSE );
1424 }
1425 status = cryptSetAttribute( cryptCert, CRYPT_ATTRIBUTE_CURRENT,
1426 CRYPT_CERTINFO_SUBJECTNAME );
1427 if( cryptStatusOK( status ) )
1428 {
1429 status = cryptGetAttribute( cryptCert, CRYPT_ATTRIBUTE_CURRENT,
1430 &value );
1431 if( cryptStatusError( status ) || \
1432 value != CRYPT_CERTINFO_SUBJECTNAME )
1433 {
1434 errorString = "Current attribute != subject DN after subject DN "
1435 "was selected";
1436 status = -1;
1437 }
1438 }
1439 #if 0 /* The following should in theory fail but doesn't because of the
1440 auto-selection of the subject altName when no other GeneralName
1441 is selected. This is required in order for reads of commonly-
1442 used fields like email addresses to work without the user having
1443 to explicitly select the subject altName (which they're likely
1444 unaware of) first. This result is slightly non-orthogonal, but
1445 given the choice of enforcing strict orthogonality in a facility
1446 that most users will never use vs. making something that's widely
1447 used work as expected, the latter is the preferable option */
1448 if( cryptStatusOK( status ) )
1449 {
1450 /* Should fail since the subject DN is the currently selected
1451 attribute */
1452 status = cryptGetAttributeString( cryptCert, CRYPT_CERTINFO_EMAIL,
1453 buffer, &length );
1454 if( cryptStatusOK( status ) )
1455 {
1456 errorString = "email from altName was returned after subject DN was selected";
1457 status = -1;
1458 }
1459 else
1460 status = CRYPT_OK;
1461 }
1462 #endif /* 0 */
1463 if( cryptStatusOK( status ) )
1464 {
1465 status = cryptGetAttributeString( cryptCert,
1466 CRYPT_CERTINFO_ORGANISATIONALUNITNAME,
1467 buffer, &length );
1468 if( cryptStatusError( status ) )
1469 errorString = "Fetch of first OU failed";
1470 }
1471 if( cryptStatusOK( status ) )
1472 {
1473 /* Should fail since there's no current attribute */
1474 status = cryptSetAttribute( cryptCert, CRYPT_ATTRIBUTE_CURRENT,
1475 CRYPT_CURSOR_NEXT );
1476 if( cryptStatusOK( status ) )
1477 {
1478 errorString = "CURSOR_NEXT succeeded when no attribute selected";
1479 status = -1;
1480 }
1481 else
1482 status = CRYPT_OK;
1483 }
1484 if( cryptStatusOK( status ) )
1485 {
1486 /* Should fail since there's no attribute instance selected */
1487 status = cryptSetAttribute( cryptCert, CRYPT_ATTRIBUTE_CURRENT_INSTANCE,
1488 CRYPT_CURSOR_NEXT );
1489 if( cryptStatusOK( status ) )
1490 {
1491 errorString = "CURSOR_NEXT succeeded when no attribute instance selected";
1492 status = -1;
1493 }
1494 else
1495 status = CRYPT_OK;
1496 }
1497 if( cryptStatusError( status ) )
1498 {
1499 printf( "%s, line %d.\n", errorString, __LINE__ );
1500 return( FALSE );
1501 }
1502 status = cryptGetAttributeString( cryptCert,
1503 CRYPT_CERTINFO_ORGANISATIONALUNITNAME,
1504 buffer, &length );
1505 if( cryptStatusOK( status ) )
1506 status = cryptSetAttribute( cryptCert, CRYPT_ATTRIBUTE_CURRENT_INSTANCE,
1507 CRYPT_CERTINFO_ORGANISATIONALUNITNAME );
1508 if( cryptStatusOK( status ) )
1509 {
1510 status = cryptGetAttribute( cryptCert, CRYPT_ATTRIBUTE_CURRENT_INSTANCE,
1511 &value );
1512 if( cryptStatusError( status ) || \
1513 value != CRYPT_CERTINFO_ORGANISATIONALUNITNAME )
1514 {
1515 errorString = "Current instance != OU after OU was selected";
1516 status = -1;
1517 }
1518 }
1519 if( cryptStatusOK( status ) )
1520 {
1521 /* Should fail since there's no current attribute */
1522 status = cryptSetAttribute( cryptCert, CRYPT_ATTRIBUTE_CURRENT,
1523 CRYPT_CURSOR_NEXT );
1524 if( cryptStatusOK( status ) )
1525 {
1526 errorString = "CURSOR_NEXT succeeded when no attribute selected";
1527 status = -1;
1528 }
1529 else
1530 status = CRYPT_OK;
1531 }
1532 if( cryptStatusOK( status ) )
1533 {
1534 status = cryptSetAttribute( cryptCert, CRYPT_ATTRIBUTE_CURRENT_INSTANCE,
1535 CRYPT_CURSOR_NEXT );
1536 if( cryptStatusError( status ) )
1537 errorString = "Move to second OU failed";
1538 }
1539 if( cryptStatusOK( status ) )
1540 {
1541 status = cryptGetAttributeString( cryptCert,
1542 CRYPT_CERTINFO_ORGANISATIONALUNITNAME,
1543 buffer, &length );
1544 if( cryptStatusError( status ) )
1545 errorString = "Fetch of second OU failed";
1546 }
1547 if( cryptStatusOK( status ) )
1548 {
1549 status = cryptSetAttribute( cryptCert, CRYPT_ATTRIBUTE_CURRENT_INSTANCE,
1550 CRYPT_CURSOR_LAST );
1551 if( cryptStatusError( status ) )
1552 errorString = "Move to last (third) OU failed";
1553 }
1554 if( cryptStatusOK( status ) )
1555 {
1556 status = cryptGetAttributeString( cryptCert,
1557 CRYPT_CERTINFO_ORGANISATIONALUNITNAME,
1558 buffer, &length );
1559 if( cryptStatusError( status ) )
1560 errorString = "Fetch of third OU failed";
1561 }
1562 if( cryptStatusError( status ) )
1563 {
1564 printf( "%s, line %d.\n", errorString, __LINE__ );
1565 return( FALSE );
1566 }
1567
1568 /* Clean up */
1569 cryptDestroyCert( cryptCert );
1570 fputs( "Certificate attribute handling succeeded.\n\n", outputStream );
1571 #else
1572 fputs( "Skipping certificate attribute handling test because support "
1573 "for the\nrequired custom DN creation has been disabled via the "
1574 "cryptlib config\noptions.\n\n", outputStream );
1575 #endif /* USE_CERT_DNSTRING */
1576 return( TRUE );
1577 }
1578
1579 static const CERT_DATA FAR_BSS setCertData[] = {
1580 /* Identification information */
1581 { CRYPT_CERTINFO_COUNTRYNAME, IS_STRING, 0, TEXT( "NZ" ) },
1582 { CRYPT_CERTINFO_ORGANIZATIONNAME, IS_STRING, 0, TEXT( "Dave's Wetaburgers and Temple of SET" ) },
1583 { CRYPT_CERTINFO_ORGANIZATIONALUNITNAME, IS_STRING, 0, TEXT( "SET Commerce Division" ) },
1584 { CRYPT_CERTINFO_COMMONNAME, IS_STRING, 0, TEXT( "Dave's Cousin Bob" ) },
1585
1586 /* Self-signed X.509v3 certificate */
1587 { CRYPT_CERTINFO_SELFSIGNED, IS_NUMERIC, TRUE },
1588
1589 /* Add the SET extensions */
1590 { CRYPT_CERTINFO_SET_CERTIFICATETYPE, IS_NUMERIC, CRYPT_SET_CERTTYPE_RCA },
1591 { CRYPT_CERTINFO_SET_CERTCARDREQUIRED, IS_NUMERIC, TRUE },
1592 { CRYPT_CERTINFO_SET_ROOTKEYTHUMBPRINT, IS_STRING, 20, TEXT( "12345678900987654321" ) },
1593 { CRYPT_CERTINFO_SET_MERID, IS_STRING, 0, TEXT( "Wetaburger Vendor" ) },
1594 { CRYPT_CERTINFO_SET_MERACQUIRERBIN, IS_STRING, 0, TEXT( "123456" ) },
1595 { CRYPT_CERTINFO_SET_MERCHANTLANGUAGE, IS_STRING, 0, TEXT( "English" ) },
1596 { CRYPT_CERTINFO_SET_MERCHANTNAME, IS_STRING, 0, TEXT( "Dave's Wetaburgers and SET Merchant" ) },
1597 { CRYPT_CERTINFO_SET_MERCHANTCITY, IS_STRING, 0, TEXT( "Eketahuna" ) },
1598 { CRYPT_CERTINFO_SET_MERCHANTCOUNTRYNAME, IS_STRING, 0, TEXT( "New Zealand" ) },
1599 { CRYPT_CERTINFO_SET_MERCOUNTRY, IS_NUMERIC, 554 }, /* ISO 3166 */
1600
1601 { CRYPT_ATTRIBUTE_NONE, 0, 0, NULL }
1602 };
1603
testSETCert(void)1604 int testSETCert( void )
1605 {
1606 #ifdef USE_CERT_OBSOLETE
1607 CRYPT_CERTIFICATE cryptCert;
1608 CRYPT_CONTEXT pubKeyContext, privKeyContext;
1609 int status;
1610
1611 fputs( "Testing SET certificate creation/export...\n", outputStream );
1612
1613 /* Create the RSA en/decryption contexts */
1614 if( !loadRSAContexts( CRYPT_UNUSED, &pubKeyContext, &privKeyContext ) )
1615 return( FALSE );
1616
1617 /* Create the certificate */
1618 status = cryptCreateCert( &cryptCert, CRYPT_UNUSED,
1619 CRYPT_CERTTYPE_CERTIFICATE );
1620 if( cryptStatusError( status ) )
1621 {
1622 fprintf( outputStream, "cryptCreateCert() failed with error "
1623 "code %d, line %d.\n", status, __LINE__ );
1624 return( FALSE );
1625 }
1626
1627 /* Add some certificate components */
1628 status = cryptSetAttribute( cryptCert,
1629 CRYPT_CERTINFO_SUBJECTPUBLICKEYINFO, pubKeyContext );
1630 if( cryptStatusError( status ) )
1631 return( attrErrorExit( cryptCert, "cryptSetAttribute()", status,
1632 __LINE__ ) );
1633 if( !addCertFields( cryptCert, setCertData, __LINE__ ) )
1634 return( FALSE );
1635
1636 /* Sign the certificate and print information on what we got */
1637 status = cryptSignCert( cryptCert, privKeyContext );
1638 if( cryptStatusError( status ) )
1639 return( attrErrorExit( cryptCert, "cryptSignCert()", status,
1640 __LINE__ ) );
1641 if( !printCertInfo( cryptCert ) )
1642 return( FALSE );
1643
1644 /* Export the certificate */
1645 status = cryptExportCert( certBuffer, BUFFER_SIZE, &certificateLength,
1646 CRYPT_CERTFORMAT_CERTIFICATE, cryptCert );
1647 if( cryptStatusError( status ) )
1648 return( attrErrorExit( cryptCert, "cryptExportCert()", status,
1649 __LINE__ ) );
1650 fprintf( outputStream, "Exported certificate is %d bytes long.\n",
1651 certificateLength );
1652 debugDump( "certset", certBuffer, certificateLength );
1653
1654 /* Destroy the certificate */
1655 status = cryptDestroyCert( cryptCert );
1656 if( cryptStatusError( status ) )
1657 {
1658 printf( "cryptDestroyCert() failed with error code %d, line %d.\n",
1659 status, __LINE__ );
1660 return( FALSE );
1661 }
1662
1663 /* Make sure that we can read what we created */
1664 status = cryptImportCert( certBuffer, certificateLength, CRYPT_UNUSED,
1665 &cryptCert );
1666 if( cryptStatusError( status ) )
1667 {
1668 fprintf( outputStream, "cryptImportCert() failed with error "
1669 "code %d, line %d.\n", status, __LINE__ );
1670 return( FALSE );
1671 }
1672 status = cryptCheckCert( cryptCert, CRYPT_UNUSED );
1673 if( cryptStatusError( status ) )
1674 return( attrErrorExit( cryptCert, "cryptCheckCert()", status,
1675 __LINE__ ) );
1676 cryptDestroyCert( cryptCert );
1677
1678 /* Clean up */
1679 destroyContexts( CRYPT_UNUSED, pubKeyContext, privKeyContext );
1680 fputs( "SET certificate creation succeeded.\n\n", outputStream );
1681 #else
1682 fputs( "Skipping SET certificate creation/export test because support "
1683 "for this\ncertificate type has been disabled via the cryptlib "
1684 "config options.\n\n", outputStream );
1685 #endif /* USE_CERT_OBSOLETE */
1686 return( TRUE );
1687 }
1688
1689 static const CERT_DATA FAR_BSS attributeCertData[] = {
1690 /* Identification information */
1691 { CRYPT_CERTINFO_COUNTRYNAME, IS_STRING, 0, TEXT( "NI" ) }, /* Ni! Ni! Ni! */
1692 { CRYPT_CERTINFO_ORGANIZATIONNAME, IS_STRING, 0, TEXT( "Dave's Wetaburgers and Attributes" ) },
1693 { CRYPT_CERTINFO_ORGANIZATIONALUNITNAME, IS_STRING, 0, TEXT( "Attribute Management" ) },
1694 { CRYPT_CERTINFO_COMMONNAME, IS_STRING, 0, TEXT( "Dave's Mum" ) },
1695
1696 { CRYPT_ATTRIBUTE_NONE, 0, 0, NULL }
1697 };
1698
testAttributeCert(void)1699 int testAttributeCert( void )
1700 {
1701 CRYPT_CERTIFICATE cryptCert;
1702 CRYPT_CONTEXT cryptAuthorityKey;
1703 int status;
1704
1705 fputs( "Testing attribute certificate creation/export...\n",
1706 outputStream );
1707
1708 /* Get the authority's private key */
1709 status = getPrivateKey( &cryptAuthorityKey, CA_PRIVKEY_FILE,
1710 CA_PRIVKEY_LABEL, TEST_PRIVKEY_PASSWORD );
1711 if( cryptStatusError( status ) )
1712 {
1713 fprintf( outputStream, "Authority private key read failed with "
1714 "error code %d, line %d.\n", status, __LINE__ );
1715 return( FALSE );
1716 }
1717
1718 /* Create the certificate */
1719 status = cryptCreateCert( &cryptCert, CRYPT_UNUSED,
1720 CRYPT_CERTTYPE_ATTRIBUTE_CERT );
1721 if( cryptStatusError( status ) )
1722 {
1723 fprintf( outputStream, "cryptCreateCert() failed with error "
1724 "code %d, line %d.\n", status, __LINE__ );
1725 return( FALSE );
1726 }
1727
1728 /* Add some certificate components. Note that we don't add any
1729 attributes because these hadn't been defined yet (at least not as of
1730 the JTC1 SC21/ITU-T Q.17/7 draft of July 1997) */
1731 if( !addCertFields( cryptCert, attributeCertData, __LINE__ ) )
1732 return( FALSE );
1733
1734 /* Sign the certificate and print information on what we got */
1735 status = cryptSignCert( cryptCert, cryptAuthorityKey );
1736 if( cryptStatusError( status ) )
1737 return( attrErrorExit( cryptCert, "cryptSignCert()", status,
1738 __LINE__ ) );
1739 if( !printCertInfo( cryptCert ) )
1740 return( FALSE );
1741
1742 /* Export the certificate */
1743 status = cryptExportCert( certBuffer, BUFFER_SIZE, &certificateLength,
1744 CRYPT_CERTFORMAT_CERTIFICATE, cryptCert );
1745 if( cryptStatusError( status ) )
1746 return( attrErrorExit( cryptCert, "cryptExportCert()", status,
1747 __LINE__ ) );
1748 fprintf( outputStream, "Exported certificate is %d bytes long.\n",
1749 certificateLength );
1750 debugDump( "certattr", certBuffer, certificateLength );
1751
1752 /* Destroy the certificate */
1753 status = cryptDestroyCert( cryptCert );
1754 if( cryptStatusError( status ) )
1755 {
1756 printf( "cryptDestroyCert() failed with error code %d, line %d.\n",
1757 status, __LINE__ );
1758 return( FALSE );
1759 }
1760
1761 /* Make sure that we can read what we created */
1762 status = cryptImportCert( certBuffer, certificateLength, CRYPT_UNUSED,
1763 &cryptCert );
1764 if( cryptStatusError( status ) )
1765 {
1766 fprintf( outputStream, "cryptImportCert() failed with error "
1767 "code %d, line %d.\n", status, __LINE__ );
1768 return( FALSE );
1769 }
1770 status = cryptCheckCert( cryptCert, cryptAuthorityKey );
1771 if( cryptStatusError( status ) )
1772 return( attrErrorExit( cryptCert, "cryptCheckCert()", status,
1773 __LINE__ ) );
1774 cryptDestroyCert( cryptCert );
1775
1776 /* Clean up */
1777 cryptDestroyContext( cryptAuthorityKey );
1778 fputs( "Attribute certificate creation succeeded.\n\n", outputStream );
1779 return( TRUE );
1780 }
1781
1782 /* Test certification request code. These create a basic certificate
1783 request, a more complex certificate request with all extensions encoded
1784 as attributes of an extensionReq, and a request with a separate PKCS #9
1785 attribute alongside the other attributes in the extensionReq */
1786
1787 static const CERT_DATA FAR_BSS certRequestData[] = {
1788 /* Identification information */
1789 { CRYPT_CERTINFO_COUNTRYNAME, IS_STRING, 0, TEXT( "PT" ) },
1790 { CRYPT_CERTINFO_ORGANIZATIONNAME, IS_STRING, 0, TEXT( "Dave's Wetaburgers" ) },
1791 { CRYPT_CERTINFO_ORGANIZATIONALUNITNAME, IS_STRING, 0, TEXT( "Procurement" ) },
1792 { CRYPT_CERTINFO_COMMONNAME, IS_STRING, 0, TEXT( "Dave Smith" ) },
1793
1794 { CRYPT_ATTRIBUTE_NONE, 0, 0, NULL }
1795 };
1796
1797 static const CERT_DATA FAR_BSS complexCertRequestData[] = {
1798 /* Identification information */
1799 { CRYPT_CERTINFO_COUNTRYNAME, IS_STRING, 0, TEXT( "NZ" ) },
1800 { CRYPT_CERTINFO_ORGANIZATIONNAME, IS_STRING, 0, TEXT( "Dave's Wetaburgers" ) },
1801 { CRYPT_CERTINFO_ORGANIZATIONALUNITNAME, IS_STRING, 0, TEXT( "Procurement" ) },
1802 { CRYPT_CERTINFO_COMMONNAME, IS_STRING, 0, TEXT( "Dave Smith" ) },
1803
1804 /* Subject altName */
1805 { CRYPT_CERTINFO_RFC822NAME, IS_STRING, 0, TEXT( "dave@wetas-r-us.com" ) },
1806 { CRYPT_CERTINFO_UNIFORMRESOURCEIDENTIFIER, IS_STRING, 0, TEXT( "http://www.wetas-r-us.com" ) },
1807
1808 /* Re-select the subject name after poking around in the altName */
1809 { CRYPT_ATTRIBUTE_CURRENT, IS_NUMERIC, CRYPT_CERTINFO_SUBJECTNAME },
1810
1811 /* SSL server and client authentication */
1812 { CRYPT_CERTINFO_EXTKEY_SERVERAUTH, IS_NUMERIC, CRYPT_UNUSED },
1813 { CRYPT_CERTINFO_EXTKEY_CLIENTAUTH, IS_NUMERIC, CRYPT_UNUSED },
1814
1815 { CRYPT_ATTRIBUTE_NONE, IS_VOID }
1816 };
1817
1818 static const CERT_DATA FAR_BSS certRequestAttrib1Data[] = {
1819 /* Identification information */
1820 { CRYPT_CERTINFO_COUNTRYNAME, IS_STRING, 0, TEXT( "PT" ) },
1821 { CRYPT_CERTINFO_ORGANIZATIONNAME, IS_STRING, 0, TEXT( "Dave's Wetaburgers" ) },
1822 { CRYPT_CERTINFO_ORGANIZATIONALUNITNAME, IS_STRING, 0, TEXT( "Procurement" ) },
1823 { CRYPT_CERTINFO_COMMONNAME, IS_STRING, 0, TEXT( "Dave Smith" ) },
1824
1825 /* Subject altName encoded as an extensionReq */
1826 { CRYPT_CERTINFO_RFC822NAME, IS_STRING, 0, TEXT( "dave@wetas-r-us.com" ) },
1827 { CRYPT_CERTINFO_UNIFORMRESOURCEIDENTIFIER, IS_STRING, 0, TEXT( "http://www.wetas-r-us.com" ) },
1828
1829 { CRYPT_ATTRIBUTE_NONE, 0, 0, NULL }
1830 };
1831
1832 static const CERT_DATA FAR_BSS certRequestAttrib2Data[] = {
1833 /* Identification information */
1834 { CRYPT_CERTINFO_COUNTRYNAME, IS_STRING, 0, TEXT( "PT" ) },
1835 { CRYPT_CERTINFO_ORGANIZATIONNAME, IS_STRING, 0, TEXT( "Dave's Wetaburgers" ) },
1836 { CRYPT_CERTINFO_ORGANIZATIONALUNITNAME, IS_STRING, 0, TEXT( "Procurement" ) },
1837 { CRYPT_CERTINFO_COMMONNAME, IS_STRING, 0, TEXT( "Dave Smith" ) },
1838
1839 /* PKCS #9 attribute that isn't encoded as an extensionReq */
1840 { CRYPT_CERTINFO_CHALLENGEPASSWORD, IS_STRING, 0, TEXT( "password" ) },
1841
1842 { CRYPT_ATTRIBUTE_NONE, 0, 0, NULL }
1843 };
1844
1845 static const CERT_DATA FAR_BSS certRequestAttrib3Data[] = {
1846 /* Identification information */
1847 { CRYPT_CERTINFO_COUNTRYNAME, IS_STRING, 0, TEXT( "PT" ) },
1848 { CRYPT_CERTINFO_ORGANIZATIONNAME, IS_STRING, 0, TEXT( "Dave's Wetaburgers" ) },
1849 { CRYPT_CERTINFO_ORGANIZATIONALUNITNAME, IS_STRING, 0, TEXT( "Procurement" ) },
1850 { CRYPT_CERTINFO_COMMONNAME, IS_STRING, 0, TEXT( "Dave Smith" ) },
1851
1852 /* Subject altName encoded as an extensionReq */
1853 { CRYPT_CERTINFO_RFC822NAME, IS_STRING, 0, TEXT( "dave@wetas-r-us.com" ) },
1854 { CRYPT_CERTINFO_UNIFORMRESOURCEIDENTIFIER, IS_STRING, 0, TEXT( "http://www.wetas-r-us.com" ) },
1855
1856 /* Re-select the subject name after poking around in the altName */
1857 { CRYPT_ATTRIBUTE_CURRENT, IS_NUMERIC, CRYPT_CERTINFO_SUBJECTNAME },
1858
1859 /* PKCS #9 attribute that isn't encoded as an extensionReq */
1860 { CRYPT_CERTINFO_CHALLENGEPASSWORD, IS_STRING, 0, TEXT( "password" ) },
1861
1862 { CRYPT_ATTRIBUTE_NONE, 0, 0, NULL }
1863 };
1864
createCertRequest(const char * description,const CRYPT_ALGO_TYPE cryptAlgo,const CERT_DATA * certInfo,const char * fileName)1865 static int createCertRequest( const char *description,
1866 const CRYPT_ALGO_TYPE cryptAlgo,
1867 const CERT_DATA *certInfo,
1868 const char *fileName )
1869 {
1870 CRYPT_CERTIFICATE cryptCert;
1871 CRYPT_CONTEXT pubKeyContext, privKeyContext;
1872 int dummy, status;
1873
1874 fprintf( outputStream, "Testing %s creation/export...\n", description );
1875
1876 /* Create the public/private key contexts */
1877 switch( cryptAlgo )
1878 {
1879 case CRYPT_ALGO_RSA:
1880 if( !loadRSAContexts( CRYPT_UNUSED, &pubKeyContext,
1881 &privKeyContext ) )
1882 return( FALSE );
1883 break;
1884
1885 case CRYPT_ALGO_DSA:
1886 if( !loadDSAContexts( CRYPT_UNUSED, &pubKeyContext,
1887 &privKeyContext ) )
1888 return( FALSE );
1889 break;
1890
1891 default:
1892 return( FALSE );
1893 }
1894
1895 /* Create the certificate object */
1896 status = cryptCreateCert( &cryptCert, CRYPT_UNUSED,
1897 CRYPT_CERTTYPE_CERTREQUEST );
1898 if( cryptStatusError( status ) )
1899 {
1900 fprintf( outputStream, "cryptCreateCert() failed with error "
1901 "code %d, line %d.\n", status, __LINE__ );
1902 return( FALSE );
1903 }
1904
1905 /* Add some certification request components */
1906 status = cryptSetAttribute( cryptCert,
1907 CRYPT_CERTINFO_SUBJECTPUBLICKEYINFO, pubKeyContext );
1908 if( cryptStatusError( status ) )
1909 return( attrErrorExit( cryptCert, "cryptSetAttribute()", status,
1910 __LINE__ ) );
1911 if( !addCertFields( cryptCert, certInfo, __LINE__ ) )
1912 return( FALSE );
1913
1914 /* Sign the certification request and print information on what we got */
1915 status = cryptSignCert( cryptCert, privKeyContext );
1916 if( cryptStatusError( status ) )
1917 return( attrErrorExit( cryptCert, "cryptSignCert()", status,
1918 __LINE__ ) );
1919 if( !printCertInfo( cryptCert ) )
1920 return( FALSE );
1921
1922 /* Check the signature. Since it's self-signed, we don't need to pass in
1923 a signature check key */
1924 status = cryptCheckCert( cryptCert, CRYPT_UNUSED );
1925 if( cryptStatusError( status ) )
1926 return( attrErrorExit( cryptCert, "cryptCheckCert()", status,
1927 __LINE__ ) );
1928
1929 /* Export the certificate */
1930 status = cryptExportCert( certBuffer, BUFFER_SIZE, &certificateLength,
1931 CRYPT_CERTFORMAT_CERTIFICATE, cryptCert );
1932 if( cryptStatusError( status ) )
1933 return( attrErrorExit( cryptCert, "cryptExportCert()", status,
1934 __LINE__ ) );
1935 fprintf( outputStream, "Exported %s is %d bytes long.\n", description,
1936 certificateLength );
1937 debugDump( fileName, certBuffer, certificateLength );
1938
1939 /* Make sure that an export in an illogical format is disallowed */
1940 status = cryptExportCert( NULL, 0, &dummy, CRYPT_CERTFORMAT_CERTCHAIN,
1941 cryptCert );
1942 if( cryptStatusError( status ) )
1943 {
1944 status = cryptExportCert( NULL, 0, &dummy,
1945 CRYPT_CERTFORMAT_TEXT_CERTCHAIN,
1946 cryptCert );
1947 }
1948 if( cryptStatusError( status ) )
1949 {
1950 status = cryptExportCert( NULL, 0, &dummy,
1951 CRYPT_CERTFORMAT_XML_CERTCHAIN,
1952 cryptCert );
1953 }
1954 if( cryptStatusOK( status ) )
1955 {
1956 printf( "Attempt to export certificate request in illogical format "
1957 "succeeded when it\n should have failed, line %d.\n",
1958 __LINE__ );
1959 return( FALSE );
1960 }
1961
1962 /* Destroy the certificate */
1963 status = cryptDestroyCert( cryptCert );
1964 if( cryptStatusError( status ) )
1965 {
1966 printf( "cryptDestroyCert() failed with error code %d, line %d.\n",
1967 status, __LINE__ );
1968 return( FALSE );
1969 }
1970
1971 /* Make sure that we can read what we created */
1972 status = cryptImportCert( certBuffer, certificateLength, CRYPT_UNUSED,
1973 &cryptCert );
1974 if( cryptStatusError( status ) )
1975 {
1976 fprintf( outputStream, "cryptImportCert() failed with error "
1977 "code %d, line %d.\n", status, __LINE__ );
1978 return( FALSE );
1979 }
1980 status = cryptCheckCert( cryptCert, CRYPT_UNUSED );
1981 if( cryptStatusError( status ) )
1982 return( attrErrorExit( cryptCert, "cryptCheckCert()", status,
1983 __LINE__ ) );
1984 cryptDestroyCert( cryptCert );
1985
1986 /* Clean up */
1987 destroyContexts( CRYPT_UNUSED, pubKeyContext, privKeyContext );
1988 fprintf( outputStream, "Creation of %s succeeded.\n\n", description );
1989 return( TRUE );
1990 }
1991
testCertRequest(void)1992 int testCertRequest( void )
1993 {
1994 if( !createCertRequest( "RSA certification request", CRYPT_ALGO_RSA,
1995 certRequestData, "certreqr" ) )
1996 return( FALSE );
1997 return( createCertRequest( "DSA certification request", CRYPT_ALGO_DSA,
1998 certRequestData, "certreqd" ) );
1999 }
2000
testComplexCertRequest(void)2001 int testComplexCertRequest( void )
2002 {
2003 return( createCertRequest( "complex certification request",
2004 CRYPT_ALGO_RSA, complexCertRequestData,
2005 "certreqc" ) );
2006 }
2007
testCertRequestAttrib(void)2008 int testCertRequestAttrib( void )
2009 {
2010 if( !createCertRequest( "cert.request with non-encapsulated attributes",
2011 CRYPT_ALGO_RSA, certRequestAttrib1Data,
2012 "certreqa1" ) )
2013 return( FALSE ); /* extReq attribute */
2014 if( !createCertRequest( "cert.request with encapsulated attributes",
2015 CRYPT_ALGO_RSA, certRequestAttrib2Data,
2016 "certreqa2" ) )
2017 return( FALSE ); /* Non-extReq attribute */
2018 return( createCertRequest( "cert.request with both types of attributes",
2019 CRYPT_ALGO_RSA, certRequestAttrib3Data,
2020 "certreqa3" ) );
2021 } /* Both types of attributes */
2022
2023 /* Test CRMF certification request code */
2024
crmfRequest(const CRYPT_ALGO_TYPE cryptAlgo)2025 static int crmfRequest( const CRYPT_ALGO_TYPE cryptAlgo )
2026 {
2027 CRYPT_CERTIFICATE cryptCert;
2028 CRYPT_CONTEXT pubKeyContext, privKeyContext;
2029 int status;
2030
2031 fprintf( outputStream, "Testing CRMF %s certification request "
2032 "creation/export...\n",
2033 ( cryptAlgo == CRYPT_ALGO_DSA ) ? "DSA" : \
2034 ( cryptAlgo == CRYPT_ALGO_ECDSA ) ? "ECDSA" : "RSA" );
2035
2036 /* Create the en/decryption contexts */
2037 switch( cryptAlgo )
2038 {
2039 case CRYPT_ALGO_DSA:
2040 if( !loadDSAContexts( CRYPT_UNUSED, &pubKeyContext,
2041 &privKeyContext ) )
2042 return( FALSE );
2043 break;
2044
2045 case CRYPT_ALGO_ECDSA:
2046 if( !loadECDSAContexts( CRYPT_UNUSED, &pubKeyContext,
2047 &privKeyContext ) )
2048 return( FALSE );
2049 break;
2050
2051 default:
2052 if( !loadRSAContexts( CRYPT_UNUSED, &pubKeyContext,
2053 &privKeyContext ) )
2054 return( FALSE );
2055 }
2056
2057 /* Create the certificate object */
2058 status = cryptCreateCert( &cryptCert, CRYPT_UNUSED,
2059 CRYPT_CERTTYPE_REQUEST_CERT );
2060 if( cryptStatusError( status ) )
2061 {
2062 fprintf( outputStream, "cryptCreateCert() failed with error "
2063 "code %d, line %d.\n", status, __LINE__ );
2064 return( FALSE );
2065 }
2066
2067 /* Add some certification request components */
2068 status = cryptSetAttribute( cryptCert,
2069 CRYPT_CERTINFO_SUBJECTPUBLICKEYINFO, pubKeyContext );
2070 if( cryptStatusError( status ) )
2071 return( attrErrorExit( cryptCert, "cryptSetAttribute()", status,
2072 __LINE__ ) );
2073 if( !addCertFields( cryptCert, certRequestData, __LINE__ ) )
2074 return( FALSE );
2075
2076 /* Sign the certification request and print information on what we got */
2077 status = cryptSignCert( cryptCert, privKeyContext );
2078 if( cryptStatusError( status ) )
2079 return( attrErrorExit( cryptCert, "cryptSignCert()", status,
2080 __LINE__ ) );
2081 if( !printCertInfo( cryptCert ) )
2082 return( FALSE );
2083
2084 /* Check the signature. Since it's self-signed, we don't need to pass in
2085 a signature check key */
2086 status = cryptCheckCert( cryptCert, CRYPT_UNUSED );
2087 if( cryptStatusError( status ) )
2088 return( attrErrorExit( cryptCert, "cryptCheckCert()", status,
2089 __LINE__ ) );
2090
2091 /* Export the certificate */
2092 status = cryptExportCert( certBuffer, BUFFER_SIZE, &certificateLength,
2093 CRYPT_CERTFORMAT_CERTIFICATE, cryptCert );
2094 if( cryptStatusError( status ) )
2095 return( attrErrorExit( cryptCert, "cryptExportCert()", status,
2096 __LINE__ ) );
2097 fprintf( outputStream, "Exported certification request is %d bytes "
2098 "long.\n", certificateLength );
2099 debugDump( ( cryptAlgo == CRYPT_ALGO_DSA ) ? "req_crmf_d" : \
2100 ( cryptAlgo == CRYPT_ALGO_ECDSA ) ? "req_crmf_ec" : "req_crmf_r",
2101 certBuffer, certificateLength );
2102
2103 /* Destroy the certificate */
2104 status = cryptDestroyCert( cryptCert );
2105 if( cryptStatusError( status ) )
2106 {
2107 printf( "cryptDestroyCert() failed with error code %d, line %d.\n",
2108 status, __LINE__ );
2109 return( FALSE );
2110 }
2111
2112 /* Make sure that we can read what we created */
2113 status = cryptImportCert( certBuffer, certificateLength, CRYPT_UNUSED,
2114 &cryptCert );
2115 if( cryptStatusError( status ) )
2116 {
2117 fprintf( outputStream, "cryptImportCert() failed with error "
2118 "code %d, line %d.\n", status, __LINE__ );
2119 return( FALSE );
2120 }
2121 status = cryptCheckCert( cryptCert, CRYPT_UNUSED );
2122 if( cryptStatusError( status ) )
2123 return( attrErrorExit( cryptCert, "cryptCheckCert()", status,
2124 __LINE__ ) );
2125 cryptDestroyCert( cryptCert );
2126
2127 /* Clean up */
2128 destroyContexts( CRYPT_UNUSED, pubKeyContext, privKeyContext );
2129 fputs( "CRMF certification request creation succeeded.\n\n",
2130 outputStream );
2131 return( TRUE );
2132 }
2133
testCRMFRequest(void)2134 int testCRMFRequest( void )
2135 {
2136 if( !crmfRequest( CRYPT_ALGO_RSA ) )
2137 return( FALSE );
2138 if( !crmfRequest( CRYPT_ALGO_DSA ) )
2139 return( FALSE );
2140 if( cryptQueryCapability( CRYPT_ALGO_ECDSA, NULL ) != CRYPT_ERROR_NOTAVAIL )
2141 {
2142 if( !crmfRequest( CRYPT_ALGO_ECDSA ) )
2143 return( FALSE );
2144 }
2145 return( TRUE );
2146 }
2147
testComplexCRMFRequest(void)2148 int testComplexCRMFRequest( void )
2149 {
2150 CRYPT_CERTIFICATE cryptCert;
2151 CRYPT_CONTEXT pubKeyContext, privKeyContext;
2152 int status;
2153
2154 fputs( "Testing complex CRMF certification request "
2155 "creation/export...\n", outputStream );
2156
2157 /* Create the RSA en/decryption contexts */
2158 if( !loadRSAContexts( CRYPT_UNUSED, &pubKeyContext, &privKeyContext ) )
2159 return( FALSE );
2160
2161 /* Create the certificate object */
2162 status = cryptCreateCert( &cryptCert, CRYPT_UNUSED,
2163 CRYPT_CERTTYPE_REQUEST_CERT );
2164 if( cryptStatusError( status ) )
2165 {
2166 fprintf( outputStream, "cryptCreateCert() failed with error "
2167 "code %d, line %d.\n", status, __LINE__ );
2168 return( FALSE );
2169 }
2170
2171 /* Add some certification request components */
2172 status = cryptSetAttribute( cryptCert,
2173 CRYPT_CERTINFO_SUBJECTPUBLICKEYINFO, pubKeyContext );
2174 if( cryptStatusError( status ) )
2175 return( attrErrorExit( cryptCert, "cryptSetAttribute()", status,
2176 __LINE__ ) );
2177 if( !addCertFields( cryptCert, complexCertRequestData, __LINE__ ) )
2178 return( FALSE );
2179
2180 /* Sign the certification request and print information on what we got */
2181 status = cryptSignCert( cryptCert, privKeyContext );
2182 if( cryptStatusError( status ) )
2183 return( attrErrorExit( cryptCert, "cryptSignCert()", status,
2184 __LINE__ ) );
2185 if( !printCertInfo( cryptCert ) )
2186 return( FALSE );
2187
2188 /* Check the signature. Since it's self-signed, we don't need to pass in
2189 a signature check key */
2190 status = cryptCheckCert( cryptCert, CRYPT_UNUSED );
2191 if( cryptStatusError( status ) )
2192 return( attrErrorExit( cryptCert, "cryptCheckCert()", status,
2193 __LINE__ ) );
2194
2195 /* Export the certificate */
2196 status = cryptExportCert( certBuffer, BUFFER_SIZE, &certificateLength,
2197 CRYPT_CERTFORMAT_CERTIFICATE, cryptCert );
2198 if( cryptStatusError( status ) )
2199 return( attrErrorExit( cryptCert, "cryptExportCert()", status,
2200 __LINE__ ) );
2201 fprintf( outputStream, "Exported certification request is %d bytes "
2202 "long.\n", certificateLength );
2203 debugDump( "req_crmfc", certBuffer, certificateLength );
2204
2205 /* Destroy the certificate */
2206 status = cryptDestroyCert( cryptCert );
2207 if( cryptStatusError( status ) )
2208 {
2209 printf( "cryptDestroyCert() failed with error code %d, line %d.\n",
2210 status, __LINE__ );
2211 return( FALSE );
2212 }
2213
2214 /* Make sure that we can read what we created */
2215 status = cryptImportCert( certBuffer, certificateLength, CRYPT_UNUSED,
2216 &cryptCert );
2217 if( cryptStatusError( status ) )
2218 {
2219 fprintf( outputStream, "cryptImportCert() failed with error "
2220 "code %d, line %d.\n", status, __LINE__ );
2221 return( FALSE );
2222 }
2223 status = cryptCheckCert( cryptCert, CRYPT_UNUSED );
2224 if( cryptStatusError( status ) )
2225 return( attrErrorExit( cryptCert, "cryptCheckCert()", status,
2226 __LINE__ ) );
2227 cryptDestroyCert( cryptCert );
2228
2229 /* Clean up */
2230 destroyContexts( CRYPT_UNUSED, pubKeyContext, privKeyContext );
2231 fputs( "Complex CRMF certification request creation succeeded.\n\n",
2232 outputStream );
2233 return( TRUE );
2234 }
2235
2236 /* Test CRL code. This one represents a bit of a chicken-and-egg problem
2237 since we need a CA certificate to create the CRL, but we can't read this
2238 until the private key file read has been tested, and that requires
2239 testing of the certificate management. At the moment we just assume that
2240 private key file reads work for this test */
2241
testCRL(void)2242 int testCRL( void )
2243 {
2244 CRYPT_CERTIFICATE cryptCRL;
2245 CRYPT_CONTEXT cryptCAKey;
2246 int status;
2247
2248 fputs( "Testing CRL creation/export...\n", outputStream );
2249
2250 /* Get the CA's private key */
2251 status = getPrivateKey( &cryptCAKey, CA_PRIVKEY_FILE,
2252 CA_PRIVKEY_LABEL, TEST_PRIVKEY_PASSWORD );
2253 if( cryptStatusError( status ) )
2254 {
2255 fprintf( outputStream, "CA private key read failed with error "
2256 "code %d, line %d.\n", status, __LINE__ );
2257 return( FALSE );
2258 }
2259
2260 /* Create the CRL */
2261 status = cryptCreateCert( &cryptCRL, CRYPT_UNUSED, CRYPT_CERTTYPE_CRL );
2262 if( cryptStatusError( status ) )
2263 {
2264 fprintf( outputStream, "cryptCreateCert() failed with error "
2265 "code %d, line %d.\n", status, __LINE__ );
2266 return( FALSE );
2267 }
2268
2269 /* Add some CRL components. In this case the CA is revoking its own
2270 key */
2271 status = cryptSetAttribute( cryptCRL, CRYPT_CERTINFO_CERTIFICATE,
2272 cryptCAKey );
2273 if( cryptStatusError( status ) )
2274 return( attrErrorExit( cryptCRL, "cryptSetAttribute()", status,
2275 __LINE__ ) );
2276
2277 /* Sign the CRL */
2278 status = cryptSignCert( cryptCRL, cryptCAKey );
2279 if( cryptStatusError( status ) )
2280 return( attrErrorExit( cryptCRL, "cryptSignCert()", status,
2281 __LINE__ ) );
2282
2283 /* Print information on what we've got */
2284 if( !printCertInfo( cryptCRL ) )
2285 return( FALSE );
2286
2287 /* Check the signature. Since we have the CA private key handy, we
2288 use that to check the signature */
2289 status = cryptCheckCert( cryptCRL, cryptCAKey );
2290 if( cryptStatusError( status ) )
2291 return( attrErrorExit( cryptCRL, "cryptCheckCert()", status,
2292 __LINE__ ) );
2293
2294 /* Export the CRL */
2295 status = cryptExportCert( certBuffer, BUFFER_SIZE, &certificateLength,
2296 CRYPT_CERTFORMAT_CERTIFICATE, cryptCRL );
2297 if( cryptStatusError( status ) )
2298 return( attrErrorExit( cryptCRL, "cryptExportCert()", status,
2299 __LINE__ ) );
2300 fprintf( outputStream, "Exported CRL is %d bytes long.\n",
2301 certificateLength );
2302 debugDump( "crl", certBuffer, certificateLength );
2303
2304 /* Destroy the CRL */
2305 status = cryptDestroyCert( cryptCRL );
2306 if( cryptStatusError( status ) )
2307 {
2308 printf( "cryptDestroyCert() failed with error code %d, line %d.\n",
2309 status, __LINE__ );
2310 return( FALSE );
2311 }
2312
2313 /* Make sure that we can read what we created */
2314 status = cryptImportCert( certBuffer, certificateLength, CRYPT_UNUSED,
2315 &cryptCRL );
2316 if( cryptStatusError( status ) )
2317 {
2318 fprintf( outputStream, "cryptImportCert() failed with error "
2319 "code %d, line %d.\n", status, __LINE__ );
2320 return( FALSE );
2321 }
2322 status = cryptCheckCert( cryptCRL, cryptCAKey );
2323 if( cryptStatusError( status ) )
2324 return( attrErrorExit( cryptCRL, "cryptCheckCert()", status,
2325 __LINE__ ) );
2326 cryptDestroyCert( cryptCRL );
2327 cryptDestroyContext( cryptCAKey );
2328
2329 /* Clean up */
2330 fputs( "CRL creation succeeded.\n\n", outputStream );
2331 return( TRUE );
2332 }
2333
2334 /* Test complex CRL code */
2335
2336 static const CERT_DATA FAR_BSS complexCRLData[] = {
2337 /* Next update time */
2338 { CRYPT_CERTINFO_NEXTUPDATE, IS_TIME, 0, NULL, CERTTIME_DATETEST + ONE_YEAR_TIME },
2339
2340 /* CRL number and delta CRL indicator */
2341 { CRYPT_CERTINFO_CRLNUMBER, IS_NUMERIC, 1 },
2342 { CRYPT_CERTINFO_DELTACRLINDICATOR, IS_NUMERIC, 2 },
2343
2344 /* Issuing distribution points */
2345 { CRYPT_ATTRIBUTE_CURRENT, IS_NUMERIC, CRYPT_CERTINFO_ISSUINGDIST_FULLNAME },
2346 { CRYPT_CERTINFO_UNIFORMRESOURCEIDENTIFIER, IS_STRING, 0, TEXT( "http://www.wetas-r-us.com" ) },
2347 { CRYPT_CERTINFO_ISSUINGDIST_USERCERTSONLY, IS_NUMERIC, TRUE },
2348
2349 { CRYPT_ATTRIBUTE_NONE, IS_VOID }
2350 };
2351
testComplexCRL(void)2352 int testComplexCRL( void )
2353 {
2354 CRYPT_CERTIFICATE cryptCRL, cryptRevokeCert;
2355 CRYPT_CONTEXT cryptCAKey;
2356 time_t revocationTime;
2357 int revocationReason DUMMY_INIT, dummy, status;
2358
2359 fputs( "Testing complex CRL creation/export...\n", outputStream );
2360
2361 /* Get the CA's private key */
2362 status = getPrivateKey( &cryptCAKey, CA_PRIVKEY_FILE,
2363 CA_PRIVKEY_LABEL, TEST_PRIVKEY_PASSWORD );
2364 if( cryptStatusError( status ) )
2365 {
2366 fprintf( outputStream, "CA private key read failed with error "
2367 "code %d, line %d.\n", status, __LINE__ );
2368 return( FALSE );
2369 }
2370
2371 /* Create the CRL */
2372 status = cryptCreateCert( &cryptCRL, CRYPT_UNUSED, CRYPT_CERTTYPE_CRL );
2373 if( cryptStatusError( status ) )
2374 {
2375 fprintf( outputStream, "cryptCreateCert() failed with error "
2376 "code %d, line %d.\n", status, __LINE__ );
2377 return( FALSE );
2378 }
2379
2380 /* Add some CRL components with per-entry attributes. In this case the
2381 CA is revoking its own key because it was compromised (would you trust
2382 this CRL?) and some keys from test certs */
2383 if( !addCertFields( cryptCRL, complexCRLData, __LINE__ ) )
2384 return( FALSE );
2385 status = cryptSetAttribute( cryptCRL, CRYPT_CERTINFO_CERTIFICATE,
2386 cryptCAKey );
2387 if( cryptStatusOK( status ) )
2388 {
2389 /* The CA key was compromised */
2390 status = cryptSetAttribute( cryptCRL,
2391 CRYPT_CERTINFO_CRLREASON,
2392 CRYPT_CRLREASON_CACOMPROMISE );
2393 }
2394 if( cryptStatusOK( status ) )
2395 {
2396 status = importCertFromTemplate( &cryptRevokeCert,
2397 CRLCERT_FILE_TEMPLATE, 1 );
2398 }
2399 if( cryptStatusOK( status ) )
2400 {
2401 status = cryptSetAttribute( cryptCRL, CRYPT_CERTINFO_CERTIFICATE,
2402 cryptRevokeCert );
2403 cryptDestroyCert( cryptRevokeCert );
2404 }
2405 if( cryptStatusOK( status ) )
2406 {
2407 /* Hold certificate, call issuer for details */
2408 status = cryptSetAttribute( cryptCRL,
2409 CRYPT_CERTINFO_CRLREASON,
2410 CRYPT_CRLREASON_CERTIFICATEHOLD );
2411 if( cryptStatusOK( status ) )
2412 {
2413 #ifdef USE_CERTLEVEL_PKIX_FULL
2414 status = cryptSetAttribute( cryptCRL,
2415 CRYPT_CERTINFO_HOLDINSTRUCTIONCODE,
2416 CRYPT_HOLDINSTRUCTION_CALLISSUER );
2417 #else
2418 status = cryptSetAttribute( cryptCRL,
2419 CRYPT_CERTINFO_HOLDINSTRUCTIONCODE,
2420 CRYPT_HOLDINSTRUCTION_CALLISSUER );
2421 if( status != CRYPT_ERROR_PARAM2 )
2422 {
2423 printf( "Addition of disabled attribute %d wasn't "
2424 "detected, line %d.\n",
2425 CRYPT_CERTINFO_HOLDINSTRUCTIONCODE, __LINE__ );
2426 return( FALSE );
2427 }
2428 status = CRYPT_OK;
2429 #endif /* USE_CERTLEVEL_PKIX_FULL */
2430 }
2431 }
2432 if( cryptStatusError( status ) )
2433 {
2434 return( attrErrorExit( cryptCRL, "cryptSetAttribute(), certificate "
2435 "#1", status, __LINE__ ) );
2436 }
2437 status = importCertFromTemplate( &cryptRevokeCert,
2438 CRLCERT_FILE_TEMPLATE, 2 );
2439 if( cryptStatusOK( status ) )
2440 {
2441 status = cryptSetAttribute( cryptCRL, CRYPT_CERTINFO_CERTIFICATE,
2442 cryptRevokeCert );
2443 cryptDestroyCert( cryptRevokeCert );
2444 }
2445 if( cryptStatusOK( status ) )
2446 {
2447 const time_t invalidityDate = CERTTIME_DATETEST - ( ONE_YEAR_TIME / 12 );
2448
2449 /* The private key was invalid some time ago. We can't go back too
2450 far because the cryptlib kernel won't allow suspiciously old
2451 dates */
2452 status = cryptSetAttributeString( cryptCRL,
2453 CRYPT_CERTINFO_INVALIDITYDATE, &invalidityDate,
2454 sizeof( time_t ) );
2455 }
2456 if( cryptStatusError( status ) )
2457 {
2458 return( attrErrorExit( cryptCRL, "cryptSetAttribute(), certificate "
2459 "#2", status, __LINE__ ) );
2460 }
2461
2462 /* Sign the CRL */
2463 status = cryptSignCert( cryptCRL, cryptCAKey );
2464 if( cryptStatusError( status ) )
2465 {
2466 return( attrErrorExit( cryptCRL, "cryptSignCert()", status,
2467 __LINE__ ) );
2468 }
2469
2470 /* Print information on what we've got */
2471 if( !printCertInfo( cryptCRL ) )
2472 return( FALSE );
2473
2474 /* Check the signature. Since we have the CA private key handy, we
2475 use that to check the signature */
2476 status = cryptCheckCert( cryptCRL, cryptCAKey );
2477 if( cryptStatusError( status ) )
2478 {
2479 return( attrErrorExit( cryptCRL, "cryptCheckCert()", status,
2480 __LINE__ ) );
2481 }
2482
2483 /* Export the CRL */
2484 status = cryptExportCert( certBuffer, BUFFER_SIZE, &certificateLength,
2485 CRYPT_CERTFORMAT_CERTIFICATE, cryptCRL );
2486 if( cryptStatusError( status ) )
2487 {
2488 return( attrErrorExit( cryptCRL, "cryptExportCert()", status,
2489 __LINE__ ) );
2490 }
2491 fprintf( outputStream, "Exported CRL is %d bytes long.\n",
2492 certificateLength );
2493 debugDump( "crlc", certBuffer, certificateLength );
2494
2495 /* Destroy the CRL */
2496 status = cryptDestroyCert( cryptCRL );
2497 if( cryptStatusError( status ) )
2498 {
2499 printf( "cryptDestroyCert() failed with error code %d, line %d.\n",
2500 status, __LINE__ );
2501 return( FALSE );
2502 }
2503
2504 /* Make sure that we can read what we created */
2505 status = cryptImportCert( certBuffer, certificateLength, CRYPT_UNUSED,
2506 &cryptCRL );
2507 if( cryptStatusError( status ) )
2508 {
2509 fprintf( outputStream, "cryptImportCert() failed with error "
2510 "code %d, line %d.\n", status, __LINE__ );
2511 return( FALSE );
2512 }
2513 status = cryptCheckCert( cryptCRL, cryptCAKey );
2514 if( cryptStatusError( status ) )
2515 {
2516 return( attrErrorExit( cryptCRL, "cryptCheckCert()", status,
2517 __LINE__ ) );
2518 }
2519
2520 /* Check the newly-revoked CA key agains the CRL */
2521 status = cryptCheckCert( cryptCAKey, cryptCRL );
2522 if( status != CRYPT_ERROR_INVALID )
2523 {
2524 printf( "Revoked certificate wasn't reported as being revoked, "
2525 "line %d.\n", __LINE__ );
2526 return( FALSE );
2527 }
2528 status = cryptGetAttributeString( cryptCRL, CRYPT_CERTINFO_REVOCATIONDATE,
2529 &revocationTime, &dummy );
2530 if( cryptStatusOK( status ) )
2531 status = cryptGetAttribute( cryptCRL, CRYPT_CERTINFO_CRLREASON,
2532 &revocationReason );
2533 if( cryptStatusError( status ) )
2534 {
2535 return( attrErrorExit( cryptCRL, "cryptGetAttribute()", status,
2536 __LINE__ ) );
2537 }
2538 if( revocationReason != CRYPT_CRLREASON_CACOMPROMISE )
2539 {
2540 printf( "Revocation reason was %d, should have been %d, line %d.\n",
2541 revocationReason, CRYPT_CRLREASON_CACOMPROMISE, __LINE__ );
2542 return( FALSE );
2543 }
2544
2545 /* Clean up */
2546 cryptDestroyCert( cryptCRL );
2547 cryptDestroyContext( cryptCAKey );
2548 fputs( "CRL creation succeeded.\n\n", outputStream );
2549 return( TRUE );
2550 }
2551
2552 /* Test revocation request code */
2553
2554 static const CERT_DATA FAR_BSS revRequestData[] = {
2555 /* Revocation reason */
2556 { CRYPT_CERTINFO_CRLREASON, IS_NUMERIC, CRYPT_CRLREASON_SUPERSEDED },
2557
2558 /* Invalidity date */
2559 { CRYPT_CERTINFO_INVALIDITYDATE, IS_TIME, 0, NULL, CERTTIME_DATETEST - ( ONE_YEAR_TIME / 12 ) },
2560
2561 { CRYPT_ATTRIBUTE_NONE, IS_VOID }
2562 };
2563
testRevRequest(void)2564 int testRevRequest( void )
2565 {
2566 CRYPT_CERTIFICATE cryptCert, cryptRequest;
2567 FILE *filePtr;
2568 BYTE buffer[ BUFFER_SIZE ];
2569 int count, status;
2570
2571 fputs( "Testing revocation request creation/export...\n", outputStream );
2572
2573 filenameFromTemplate( buffer, CERT_FILE_TEMPLATE, 1 );
2574 if( ( filePtr = fopen( buffer, "rb" ) ) == NULL )
2575 {
2576 puts( "Couldn't find certificate file for revocation request test." );
2577 return( FALSE );
2578 }
2579 count = fread( buffer, 1, BUFFER_SIZE, filePtr );
2580 fclose( filePtr );
2581 status = cryptImportCert( buffer, count, CRYPT_UNUSED, &cryptCert );
2582 if( cryptStatusError( status ) )
2583 {
2584 fputs( "Certificate import failed, skipping test of revocation "
2585 "request...\n", outputStream );
2586 return( TRUE );
2587 }
2588
2589 /* Create the certificate object and add the certificate details and
2590 revocation info */
2591 status = cryptCreateCert( &cryptRequest, CRYPT_UNUSED,
2592 CRYPT_CERTTYPE_REQUEST_REVOCATION );
2593 if( cryptStatusError( status ) )
2594 {
2595 fprintf( outputStream, "cryptCreateCert() failed with error "
2596 "code %d, line %d.\n", status, __LINE__ );
2597 return( FALSE );
2598 }
2599 status = cryptSetAttribute( cryptRequest, CRYPT_CERTINFO_CERTIFICATE,
2600 cryptCert );
2601 cryptDestroyCert( cryptCert );
2602 if( cryptStatusError( status ) )
2603 return( attrErrorExit( cryptRequest, "cryptSetAttribute()", status,
2604 __LINE__ ) );
2605 if( !addCertFields( cryptRequest, revRequestData, __LINE__ ) )
2606 return( FALSE );
2607
2608 /* Print information on what we've got */
2609 if( !printCertInfo( cryptRequest ) )
2610 return( FALSE );
2611
2612 #if 0 /* CMP doesn't currently allow revocation requests to be signed, so
2613 it's treated like CMS attributes as a series of uninitialised
2614 attributes */
2615 /* Export the certificate */
2616 status = cryptExportCert( certBuffer, BUFFER_SIZE, &certificateLength,
2617 CRYPT_CERTFORMAT_CERTIFICATE, cryptRequest );
2618 if( cryptStatusError( status ) )
2619 return( attrErrorExit( cryptRequest, "cryptExportCert()", status,
2620 __LINE__ ) );
2621 fprintf( outputStream, "Exported revocation request is %d bytes "
2622 "long.\n", certificateLength );
2623 debugDump( "req_rev", certBuffer, certificateLength );
2624
2625 /* Destroy the certificate */
2626 status = cryptDestroyCert( cryptRequest );
2627 if( cryptStatusError( status ) )
2628 {
2629 printf( "cryptDestroyCert() failed with error code %d, line %d.\n",
2630 status, __LINE__ );
2631 return( FALSE );
2632 }
2633
2634 /* Make sure that we can read what we created */
2635 status = cryptImportCert( certBuffer, certificateLength, CRYPT_UNUSED,
2636 &cryptRequest );
2637 if( cryptStatusError( status ) )
2638 {
2639 fprintf( outputStream, "cryptImportCert() failed with error "
2640 "code %d, line %d.\n", status, __LINE__ );
2641 return( FALSE );
2642 }
2643 #endif /* 0 */
2644 cryptDestroyCert( cryptRequest );
2645
2646 /* Clean up */
2647 fputs( "Revocation request creation succeeded.\n\n", outputStream );
2648 return( TRUE );
2649 }
2650
2651 /* Test certificate chain creation */
2652
2653 static const CERT_DATA FAR_BSS certRequestNoDNData[] = {
2654 /* Identification information. There's no DN, only a subject altName.
2655 This type of identifier is only possible with a CA-signed certificate
2656 since it contains an empty DN */
2657 { CRYPT_CERTINFO_RFC822NAME, IS_STRING, 0, TEXT( "dave@wetas-r-us.com" ) },
2658
2659 { CRYPT_ATTRIBUTE_NONE, 0, 0, NULL }
2660 };
2661
createChain(CRYPT_CERTIFICATE * cryptCertChain,const CRYPT_CONTEXT cryptCAKey,const BOOLEAN useEmptyDN,const BOOLEAN reportError)2662 static int createChain( CRYPT_CERTIFICATE *cryptCertChain,
2663 const CRYPT_CONTEXT cryptCAKey,
2664 const BOOLEAN useEmptyDN, const BOOLEAN reportError )
2665 {
2666 CRYPT_CONTEXT pubKeyContext, privKeyContext;
2667 int status;
2668
2669 /* Create the certificate chain */
2670 status = cryptCreateCert( cryptCertChain, CRYPT_UNUSED,
2671 CRYPT_CERTTYPE_CERTCHAIN );
2672 if( cryptStatusError( status ) )
2673 {
2674 fprintf( outputStream, "cryptCreateCert() failed with error "
2675 "code %d, line %d.\n", status, __LINE__ );
2676 return( FALSE );
2677 }
2678
2679 /* Create a simple certificate request to turn into the end-user
2680 certificate */
2681 if( !loadRSAContexts( CRYPT_UNUSED, &pubKeyContext, &privKeyContext ) )
2682 return( FALSE );
2683 status = cryptSetAttribute( *cryptCertChain,
2684 CRYPT_CERTINFO_SUBJECTPUBLICKEYINFO, pubKeyContext );
2685 if( cryptStatusOK( status ) && \
2686 !addCertFields( *cryptCertChain, useEmptyDN ? \
2687 certRequestNoDNData : certRequestData,
2688 __LINE__ ) )
2689 return( FALSE );
2690 destroyContexts( CRYPT_UNUSED, pubKeyContext, privKeyContext );
2691 if( cryptStatusError( status ) )
2692 {
2693 fprintf( outputStream, "Certificate creation failed with "
2694 "status %d, line %d.\n", status, __LINE__ );
2695 return( FALSE );
2696 }
2697
2698 /* Sign the leaf of the certificate chain */
2699 status = cryptSignCert( *cryptCertChain, cryptCAKey );
2700 if( cryptStatusError( status ) )
2701 {
2702 cryptDestroyCert( *cryptCertChain );
2703 if( !reportError )
2704 return( -1 );
2705 return( attrErrorExit( *cryptCertChain, "cryptSignCert()", status,
2706 __LINE__ ) );
2707 }
2708
2709 return( TRUE );
2710 }
2711
testCertChain(void)2712 int testCertChain( void )
2713 {
2714 CRYPT_CERTIFICATE cryptCertChain;
2715 CRYPT_CONTEXT cryptCAKey;
2716 int value, status;
2717
2718 fputs( "Testing certificate chain creation/export...\n", outputStream );
2719
2720 /* Get the CA's private key */
2721 status = getPrivateKey( &cryptCAKey, CA_PRIVKEY_FILE,
2722 CA_PRIVKEY_LABEL, TEST_PRIVKEY_PASSWORD );
2723 if( cryptStatusError( status ) )
2724 {
2725 fprintf( outputStream, "CA private key read failed with error "
2726 "code %d, line %d.\n", status, __LINE__ );
2727 return( FALSE );
2728 }
2729
2730 /* Create a new certificate chain */
2731 if( !createChain( &cryptCertChain, cryptCAKey, FALSE, TRUE ) )
2732 return( FALSE );
2733
2734 /* Check the signature. Since the chain counts as self-signed, we don't
2735 have to supply a sig.check key. Since the DIY CA certificate isn't
2736 trusted we have to force cryptlib to treat it as explicitly trusted
2737 when we try to verify the chain */
2738 status = setRootTrust( cryptCertChain, &value, 1 );
2739 if( cryptStatusError( status ) )
2740 return( attrErrorExit( cryptCertChain, "Setting certificate chain "
2741 "trusted", status, __LINE__ ) );
2742 status = cryptCheckCert( cryptCertChain, CRYPT_UNUSED );
2743 setRootTrust( cryptCertChain, NULL, value );
2744 if( cryptStatusError( status ) )
2745 return( attrErrorExit( cryptCertChain, "cryptCheckCert()", status,
2746 __LINE__ ) );
2747
2748 /* Try the other way of verifying the chain, by making the signing key
2749 implicitly trusted */
2750 status = cryptSetAttribute( cryptCAKey, CRYPT_CERTINFO_TRUSTED_IMPLICIT,
2751 TRUE );
2752 if( cryptStatusError( status ) )
2753 return( attrErrorExit( cryptCertChain, "Setting chain signing key "
2754 "trusted", status, __LINE__ ) );
2755 status = cryptCheckCert( cryptCertChain, CRYPT_UNUSED );
2756 cryptSetAttribute( cryptCAKey, CRYPT_CERTINFO_TRUSTED_IMPLICIT, FALSE );
2757 if( cryptStatusError( status ) )
2758 return( attrErrorExit( cryptCertChain, "cryptCheckCert()", status,
2759 __LINE__ ) );
2760
2761 /* Finally, make sure that the non-trusted chain doesn't verify */
2762 status = cryptCheckCert( cryptCertChain, CRYPT_UNUSED );
2763 if( cryptStatusOK( status ) )
2764 {
2765 printf( "Certificate chain verified OK even though it wasn't "
2766 "trusted, line %d.\n", __LINE__ );
2767 return( FALSE );
2768 }
2769
2770 /* Export the certificate chain */
2771 status = cryptExportCert( certBuffer, BUFFER_SIZE, &certificateLength,
2772 CRYPT_CERTFORMAT_CERTCHAIN, cryptCertChain );
2773 if( cryptStatusError( status ) )
2774 return( attrErrorExit( cryptCertChain, "cryptExportCert()", status,
2775 __LINE__ ) );
2776 fprintf( outputStream, "Exported certificate chain is %d bytes long.\n",
2777 certificateLength );
2778 debugDump( "certchn", certBuffer, certificateLength );
2779
2780 /* Export the chain in the various text formats to make sure that each
2781 one works correctly */
2782 if( !checkExportCert( cryptCertChain, TRUE,
2783 CRYPT_CERTFORMAT_TEXT_CERTIFICATE,
2784 "CRYPT_CERTFORMAT_TEXT_CERTIFICATE" ) )
2785 return( FALSE );
2786 if( !checkExportCert( cryptCertChain, TRUE,
2787 CRYPT_CERTFORMAT_TEXT_CERTCHAIN,
2788 "CRYPT_CERTFORMAT_TEXT_CERTCHAIN" ) )
2789 return( FALSE );
2790 if( !checkExportCert( cryptCertChain, TRUE,
2791 CRYPT_CERTFORMAT_XML_CERTIFICATE,
2792 "CRYPT_CERTFORMAT_XML_CERTIFICATE" ) )
2793 return( FALSE );
2794 if( !checkExportCert( cryptCertChain, TRUE,
2795 CRYPT_CERTFORMAT_XML_CERTCHAIN,
2796 "CRYPT_CERTFORMAT_XML_CERTCHAIN" ) )
2797 return( FALSE );
2798
2799 /* Destroy the certificate chain */
2800 status = cryptDestroyCert( cryptCertChain );
2801 if( cryptStatusError( status ) )
2802 {
2803 printf( "cryptDestroyCert() failed with error code %d, line %d.\n",
2804 status, __LINE__ );
2805 return( FALSE );
2806 }
2807
2808 /* Make sure that we can read what we created */
2809 status = cryptImportCert( certBuffer, certificateLength, CRYPT_UNUSED,
2810 &cryptCertChain );
2811 if( cryptStatusError( status ) )
2812 {
2813 fprintf( outputStream, "cryptImportCert() failed with error "
2814 "code %d, line %d.\n", status, __LINE__ );
2815 return( FALSE );
2816 }
2817 fprintf( outputStream, "Checking signatures... " );
2818 status = setRootTrust( cryptCertChain, &value, 1 );
2819 if( cryptStatusError( status ) )
2820 return( attrErrorExit( cryptCertChain, "Setting certificate chain "
2821 "trusted", status, __LINE__ ) );
2822 status = cryptCheckCert( cryptCertChain, CRYPT_UNUSED );
2823 setRootTrust( cryptCertChain, NULL, value );
2824 if( cryptStatusError( status ) )
2825 return( attrErrorExit( cryptCertChain, "cryptCheckCert()", status,
2826 __LINE__ ) );
2827 fputs( "signatures verified.\n", outputStream );
2828
2829 /* Display info on each certificate in the chain */
2830 if( !printCertChainInfo( cryptCertChain ) )
2831 return( FALSE );
2832
2833 /* Create a second certificate chain with a null DN. For this to
2834 succeed we have to set the compliance level to
2835 CRYPT_COMPLIANCELEVEL_PKIX_FULL */
2836 cryptDestroyCert( cryptCertChain );
2837 status = createChain( &cryptCertChain, cryptCAKey, TRUE, FALSE );
2838 if( status != -1 )
2839 {
2840 fprintf( outputStream, "Attempt to create certificate with null "
2841 "DN %s, line %d.\n",
2842 ( status == FALSE ) ? \
2843 "failed" : "succeeded when it should have failed",
2844 __LINE__ );
2845 return( FALSE );
2846 }
2847 ( void ) cryptGetAttribute( CRYPT_UNUSED,
2848 CRYPT_OPTION_CERT_COMPLIANCELEVEL, &value );
2849 status = cryptSetAttribute( CRYPT_UNUSED,
2850 CRYPT_OPTION_CERT_COMPLIANCELEVEL,
2851 CRYPT_COMPLIANCELEVEL_PKIX_FULL );
2852 if( cryptStatusError( status ) )
2853 {
2854 /* If the maximum level of PKIX weirdness that cryptlib will allow
2855 is less than CRYPT_COMPLIANCELEVEL_PKIX_FULL then we can't
2856 perform this test, so we just skip it */
2857 if( status != CRYPT_ERROR_PARAM3 )
2858 {
2859 printf( "Attempt to set compliance level to "
2860 "CRYPT_COMPLIANCELEVEL_PKIX_FULL failed with error code "
2861 "%d, line %d.\n", status, __LINE__ );
2862 return( FALSE );
2863 }
2864 fputs( "(Couldn't set compliance level to "
2865 "CRYPT_COMPLIANCELEVEL_PKIX_FULL, probably\n because cryptlib "
2866 "has been configured not to use this level, skipping final\n"
2867 " tests...).\n", outputStream );
2868 }
2869 else
2870 {
2871 status = createChain( &cryptCertChain, cryptCAKey, TRUE, TRUE );
2872 cryptSetAttribute( CRYPT_UNUSED, CRYPT_OPTION_CERT_COMPLIANCELEVEL,
2873 value );
2874 if( status != TRUE )
2875 {
2876 puts( " (This may be because the internal compliance-level "
2877 "handling is wrong)." );
2878 return( FALSE );
2879 }
2880 status = cryptExportCert( certBuffer, BUFFER_SIZE, &certificateLength,
2881 CRYPT_CERTFORMAT_CERTCHAIN, cryptCertChain );
2882 cryptDestroyCert( cryptCertChain );
2883 if( cryptStatusError( status ) )
2884 return( attrErrorExit( cryptCertChain, "cryptExportCert()",
2885 status, __LINE__ ) );
2886 debugDump( "certchndn", certBuffer, certificateLength );
2887 status = cryptImportCert( certBuffer, certificateLength, CRYPT_UNUSED,
2888 &cryptCertChain );
2889 if( cryptStatusError( status ) )
2890 {
2891 fprintf( outputStream, "cryptImportCert() failed with error "
2892 "code %d, line %d.\n", status, __LINE__ );
2893 return( FALSE );
2894 }
2895 }
2896
2897 /* Clean up */
2898 cryptDestroyCert( cryptCertChain );
2899 cryptDestroyContext( cryptCAKey );
2900 fputs( "Certificate chain creation succeeded.\n\n", outputStream );
2901 return( TRUE );
2902 }
2903
2904 /* Test CMS attribute code. This doesn't actually test much since this
2905 object type is just a basic data container used for the extended signing
2906 functions */
2907
2908 static const CERT_DATA FAR_BSS cmsAttributeData[] = {
2909 /* Content type and an S/MIME capability */
2910 { CRYPT_CERTINFO_CMS_CONTENTTYPE, IS_NUMERIC, CRYPT_CONTENT_SIGNEDDATA },
2911 { CRYPT_CERTINFO_CMS_SMIMECAP_PREFERSIGNEDDATA, IS_NUMERIC, CRYPT_UNUSED },
2912
2913 { CRYPT_ATTRIBUTE_NONE, IS_VOID }
2914 };
2915
testCMSAttributes(void)2916 int testCMSAttributes( void )
2917 {
2918 CRYPT_CERTIFICATE cryptAttributes;
2919 int status;
2920
2921 fputs( "Testing CMS attribute creation...\n", outputStream );
2922
2923 /* Create the CMS attribute container */
2924 status = cryptCreateCert( &cryptAttributes, CRYPT_UNUSED,
2925 CRYPT_CERTTYPE_CMS_ATTRIBUTES );
2926 if( cryptStatusError( status ) )
2927 {
2928 fprintf( outputStream, "cryptCreateCert() failed with error "
2929 "code %d, line %d.\n", status, __LINE__ );
2930 return( FALSE );
2931 }
2932
2933 /* Add some CMS attribute components */
2934 if( !addCertFields( cryptAttributes, cmsAttributeData, __LINE__ ) )
2935 return( FALSE );
2936
2937 /* Print information on what we've got */
2938 if( !printCertInfo( cryptAttributes ) )
2939 return( FALSE );
2940
2941 /* Destroy the attributes. We can't do much more than this at this
2942 stage since the attributes are only used internally by other
2943 functions */
2944 status = cryptDestroyCert( cryptAttributes );
2945 if( cryptStatusError( status ) )
2946 {
2947 printf( "cryptDestroyCert() failed with error code %d, line %d.\n",
2948 status, __LINE__ );
2949 return( FALSE );
2950 }
2951
2952 /* Clean up */
2953 fputs( "CMS attribute creation succeeded.\n\n", outputStream );
2954 return( TRUE );
2955 }
2956
2957 /* Test RTCS request/response code. This test routine itself doesn't
2958 actually test much since this object type is just a basic data container
2959 used for RTCS sessions, however the shared initRTCS() routine is used by
2960 the RTCS session code to test the rest of the functionality.
2961
2962 initRTCS() is also called by the RTCS session code, which is why it's
2963 declared non-static */
2964
initRTCS(CRYPT_CERTIFICATE * cryptRTCSRequest,const CRYPT_CERTIFICATE cryptCert,const BOOLEAN multipleCerts)2965 int initRTCS( CRYPT_CERTIFICATE *cryptRTCSRequest,
2966 const CRYPT_CERTIFICATE cryptCert,
2967 const BOOLEAN multipleCerts )
2968 {
2969 CRYPT_CERTIFICATE cryptErrorObject;
2970 C_CHR rtcsURL[ 512 ];
2971 int count DUMMY_INIT, status;
2972
2973 /* Select the RTCS responder location from the EE certificate and read
2974 the URL/FQDN value (this isn't used but is purely for display to the
2975 user) */
2976 status = cryptSetAttribute( cryptCert, CRYPT_ATTRIBUTE_CURRENT,
2977 CRYPT_CERTINFO_AUTHORITYINFO_RTCS );
2978 if( cryptStatusOK( status ) )
2979 {
2980 status = cryptGetAttributeString( cryptCert,
2981 CRYPT_CERTINFO_UNIFORMRESOURCEIDENTIFIER,
2982 rtcsURL, &count );
2983 if( status == CRYPT_ERROR_NOTFOUND )
2984 status = cryptGetAttributeString( cryptCert,
2985 CRYPT_CERTINFO_DNSNAME, rtcsURL, &count );
2986 }
2987 if( cryptStatusError( status ) )
2988 {
2989 if( status == CRYPT_ERROR_NOTFOUND )
2990 {
2991 puts( "RTCS responder URL not present in certificate, server "
2992 "name must be provided\n externally." );
2993 }
2994 else
2995 {
2996 printf( "Attempt to read RTCS responder URL failed with error "
2997 "code %d, line %d.\n", status, __LINE__ );
2998 printErrorAttributeInfo( cryptCert );
2999 return( FALSE );
3000 }
3001 }
3002 else
3003 {
3004 #ifdef UNICODE_STRINGS
3005 rtcsURL[ count / sizeof( wchar_t ) ] = TEXT( '\0' );
3006 fprintf( outputStream, "RTCS responder URL = %sS.\n", rtcsURL );
3007 #else
3008 rtcsURL[ count ] = '\0';
3009 fprintf( outputStream, "RTCS responder URL = %s.\n", rtcsURL );
3010 #endif /* UNICODE_STRINGS */
3011 }
3012
3013 /* Create the RTCS request container */
3014 status = cryptCreateCert( cryptRTCSRequest, CRYPT_UNUSED,
3015 CRYPT_CERTTYPE_RTCS_REQUEST );
3016 if( cryptStatusError( status ) )
3017 {
3018 fprintf( outputStream, "cryptCreateCert() failed with error "
3019 "code %d, line %d.\n", status, __LINE__ );
3020 return( FALSE );
3021 }
3022 cryptErrorObject = *cryptRTCSRequest;
3023
3024 /* Add the request components */
3025 status = cryptSetAttribute( *cryptRTCSRequest,
3026 CRYPT_CERTINFO_CERTIFICATE, cryptCert );
3027 if( status == CRYPT_ERROR_PARAM3 )
3028 cryptErrorObject = cryptCert;
3029 if( cryptStatusError( status ) )
3030 return( attrErrorExit( cryptErrorObject, "cryptSetAttribute()",
3031 status, __LINE__ ) );
3032
3033 /* If we're doing a query with multiple certs, add another certificate.
3034 To keep things simple and avoid having to stockpile a whole
3035 collection of certificates for each responder we just use a random
3036 certificate for which we expect an 'unknown' response */
3037 if( multipleCerts )
3038 {
3039 CRYPT_CERTIFICATE cryptSecondCert;
3040
3041 status = importCertFromTemplate( &cryptSecondCert,
3042 CERT_FILE_TEMPLATE, 1 );
3043 if( cryptStatusOK( status ) )
3044 {
3045 status = cryptSetAttribute( *cryptRTCSRequest,
3046 CRYPT_CERTINFO_CERTIFICATE,
3047 cryptSecondCert );
3048 if( status == CRYPT_ERROR_PARAM3 )
3049 cryptErrorObject = cryptSecondCert;
3050 }
3051 if( cryptStatusError( status ) )
3052 return( attrErrorExit( cryptErrorObject, "cryptSetAttribute()",
3053 status, __LINE__ ) );
3054 cryptDestroyCert( cryptSecondCert );
3055 }
3056
3057 return( TRUE );
3058 }
3059
testRTCSReqResp(void)3060 int testRTCSReqResp( void )
3061 {
3062 CRYPT_CERTIFICATE cryptRTCSRequest, cryptCert;
3063 int status;
3064
3065 fputs( "Testing RTCS request creation...\n", outputStream );
3066
3067 /* Import the EE certificate for the RTCS request */
3068 status = importCertFromTemplate( &cryptCert, RTCS_FILE_TEMPLATE,
3069 1 );
3070 if( cryptStatusError( status ) )
3071 {
3072 fprintf( outputStream, "cryptImportCert() failed with error "
3073 "code %d, line %d.\n", status, __LINE__ );
3074 return( FALSE );
3075 }
3076
3077 /* Create the RTCS request using the certs and print information on what
3078 we've got */
3079 if( !initRTCS( &cryptRTCSRequest, cryptCert, FALSE ) )
3080 return( FALSE );
3081 cryptDestroyCert( cryptCert );
3082 if( !printCertInfo( cryptRTCSRequest ) )
3083 return( FALSE );
3084
3085 /* Destroy the request. We can't do much more than this at this stage
3086 since the request is only used internally by the RTCS session code */
3087 status = cryptDestroyCert( cryptRTCSRequest );
3088 if( cryptStatusError( status ) )
3089 {
3090 printf( "cryptDestroyCert() failed with error code %d, line %d.\n",
3091 status, __LINE__ );
3092 return( FALSE );
3093 }
3094
3095 fputs( "RTCS request creation succeeded.\n\n", outputStream );
3096 return( TRUE );
3097 }
3098
3099 /* Test OCSP request/response code. This test routine itself doesn't
3100 actually test much since this object type is just a basic data container
3101 used for OCSP sessions, however the shared initOCSP() routine is used by
3102 the OCSP session code to test the rest of the functionality */
3103
initOCSP(CRYPT_CERTIFICATE * cryptOCSPRequest,CRYPT_CERTIFICATE * cert1,CRYPT_CERTIFICATE * cert2,const int number,const BOOLEAN ocspv2,const BOOLEAN revokedCert,const BOOLEAN multipleCerts,const CRYPT_SIGNATURELEVEL_TYPE sigLevel,const CRYPT_CONTEXT privKeyContext)3104 int initOCSP( CRYPT_CERTIFICATE *cryptOCSPRequest,
3105 CRYPT_CERTIFICATE *cert1, CRYPT_CERTIFICATE *cert2,
3106 const int number, const BOOLEAN ocspv2,
3107 const BOOLEAN revokedCert, const BOOLEAN multipleCerts,
3108 const CRYPT_SIGNATURELEVEL_TYPE sigLevel,
3109 const CRYPT_CONTEXT privKeyContext )
3110 {
3111 CRYPT_CERTIFICATE cryptOCSPEE = CRYPT_UNUSED, cryptOCSPEE2 = CRYPT_UNUSED;
3112 CRYPT_CERTIFICATE cryptOCSPCA, cryptErrorObject;
3113 C_CHR ocspURL[ 512 ];
3114 int count DUMMY_INIT, status;
3115
3116 assert( ( cert1 == NULL && cert2 == NULL ) || \
3117 ( cert1 != NULL && cert2 != NULL ) );
3118 assert( !ocspv2 );
3119
3120 /* Clear return values */
3121 if( cert1 != NULL )
3122 *cert1 = *cert2 = CRYPT_UNUSED;
3123
3124 /* Import the OCSP CA (if required) and EE certs */
3125 if( !ocspv2 )
3126 {
3127 status = importCertFromTemplate( &cryptOCSPCA,
3128 OCSP_CA_FILE_TEMPLATE, number );
3129 if( cryptStatusError( status ) )
3130 {
3131 fprintf( outputStream, "CA cryptImportCert() failed with "
3132 "error code %d, line %d.\n", status, __LINE__ );
3133 return( FALSE );
3134 }
3135 }
3136 status = importCertFromTemplate( &cryptOCSPEE, revokedCert ? \
3137 OCSP_EEREV_FILE_TEMPLATE: OCSP_EEOK_FILE_TEMPLATE,
3138 number );
3139 if( cryptStatusError( status ) )
3140 {
3141 fprintf( outputStream, "EE cryptImportCert() failed with "
3142 "error code %d, line %d.\n", status, __LINE__ );
3143 return( FALSE );
3144 }
3145
3146 /* Select the OCSP responder location from the EE certificate and read
3147 the URL/FQDN value (this isn't used but is purely for display to the
3148 user) */
3149 status = cryptSetAttribute( cryptOCSPEE, CRYPT_ATTRIBUTE_CURRENT,
3150 CRYPT_CERTINFO_AUTHORITYINFO_OCSP );
3151 if( cryptStatusOK( status ) )
3152 {
3153 status = cryptGetAttributeString( cryptOCSPEE,
3154 CRYPT_CERTINFO_UNIFORMRESOURCEIDENTIFIER,
3155 ocspURL, &count );
3156 if( status == CRYPT_ERROR_NOTFOUND )
3157 status = cryptGetAttributeString( cryptOCSPEE,
3158 CRYPT_CERTINFO_DNSNAME, ocspURL, &count );
3159 }
3160 if( cryptStatusError( status ) )
3161 {
3162 if( status == CRYPT_ERROR_NOTFOUND )
3163 {
3164 fputs( "OCSP responder URL not present in certificate, server "
3165 "name must be provided\n externally.\n", outputStream );
3166 }
3167 else
3168 {
3169 printf( "Attempt to read OCSP responder URL failed with error "
3170 "code %d, line %d.\n", status, __LINE__ );
3171 printErrorAttributeInfo( cryptOCSPEE );
3172 return( FALSE );
3173 }
3174 }
3175 else
3176 {
3177 #ifdef UNICODE_STRINGS
3178 ocspURL[ count / sizeof( wchar_t ) ] = TEXT( '\0' );
3179 fprintf( outputStream, "OCSP responder URL = %S.\n", ocspURL );
3180 #else
3181 ocspURL[ count ] = '\0';
3182 fprintf( outputStream, "OCSP responder URL = %s.\n", ocspURL );
3183 #endif /* UNICODE_STRINGS */
3184 }
3185
3186 /* Create the OCSP request container */
3187 status = cryptCreateCert( cryptOCSPRequest, CRYPT_UNUSED,
3188 CRYPT_CERTTYPE_OCSP_REQUEST );
3189 if( cryptStatusError( status ) )
3190 {
3191 fprintf( outputStream, "cryptCreateCert() failed with error "
3192 "code %d, line %d.\n", status, __LINE__ );
3193 return( FALSE );
3194 }
3195 cryptErrorObject = *cryptOCSPRequest;
3196
3197 /* Add the request components. Note that if we're using v1 we have to
3198 add the CA certificate first since it's needed to generate the
3199 request ID for the EE certificate */
3200 if( !ocspv2 )
3201 {
3202 status = cryptSetAttribute( *cryptOCSPRequest,
3203 CRYPT_CERTINFO_CACERTIFICATE, cryptOCSPCA );
3204 if( status == CRYPT_ERROR_PARAM3 )
3205 cryptErrorObject = cryptOCSPCA;
3206 }
3207 if( cryptStatusOK( status ) )
3208 {
3209 status = cryptSetAttribute( *cryptOCSPRequest,
3210 CRYPT_CERTINFO_CERTIFICATE, cryptOCSPEE );
3211 if( status == CRYPT_ERROR_PARAM3 )
3212 cryptErrorObject = cryptOCSPEE;
3213 }
3214 if( cryptStatusError( status ) )
3215 return( attrErrorExit( cryptErrorObject, "cryptSetAttribute()",
3216 status, __LINE__ ) );
3217
3218 /* If we're doing a query with multiple certs, add another certificate.
3219 To keep things simple and avoid having to stockpile a whole
3220 collection of certificates for each responder we just use a random
3221 certificate for which we expect an 'unknown' response */
3222 if( multipleCerts )
3223 {
3224 status = importCertFromTemplate( &cryptOCSPEE2, CERT_FILE_TEMPLATE, 1 );
3225 if( cryptStatusOK( status ) )
3226 {
3227 status = cryptSetAttribute( *cryptOCSPRequest,
3228 CRYPT_CERTINFO_CERTIFICATE, cryptOCSPEE2 );
3229 if( status == CRYPT_ERROR_PARAM3 )
3230 cryptErrorObject = cryptOCSPEE2;
3231 }
3232 if( cryptStatusError( status ) )
3233 return( attrErrorExit( *cryptOCSPRequest, "cryptSetAttribute()",
3234 status, __LINE__ ) );
3235 }
3236
3237 /* If we have a signing key, create a signed request */
3238 if( privKeyContext != CRYPT_UNUSED )
3239 {
3240 status = cryptSetAttribute( *cryptOCSPRequest,
3241 CRYPT_CERTINFO_SIGNATURELEVEL, sigLevel );
3242 if( cryptStatusError( status ) )
3243 return( attrErrorExit( *cryptOCSPRequest, "cryptSetAttribute()",
3244 status, __LINE__ ) );
3245 status = cryptSignCert( *cryptOCSPRequest, privKeyContext );
3246 if( status == CRYPT_ERROR_PARAM3 )
3247 cryptErrorObject = privKeyContext;
3248 if( cryptStatusError( status ) )
3249 return( attrErrorExit( cryptErrorObject, "cryptSignCert()",
3250 status, __LINE__ ) );
3251 }
3252
3253 /* Clean up */
3254 if( !ocspv2 )
3255 cryptDestroyCert( cryptOCSPCA );
3256 if( cert1 == NULL )
3257 {
3258 cryptDestroyCert( cryptOCSPEE );
3259 if( cryptOCSPEE != CRYPT_UNUSED )
3260 cryptDestroyCert( cryptOCSPEE2 );
3261 }
3262 else
3263 {
3264 /* Return the certificates to the caller */
3265 *cert1 = cryptOCSPEE;
3266 *cert2 = cryptOCSPEE2;
3267 }
3268
3269 return( TRUE );
3270 }
3271
testOCSPReqResp(void)3272 int testOCSPReqResp( void )
3273 {
3274 CRYPT_CERTIFICATE cryptOCSPRequest;
3275 CRYPT_CONTEXT cryptPrivateKey;
3276 int status;
3277
3278 fputs( "Testing OCSP request creation...\n", outputStream );
3279
3280 /* Create the OCSP request using the certs and print information on what
3281 we've got */
3282 if( !initOCSP( &cryptOCSPRequest, NULL, NULL, 1, FALSE, FALSE, FALSE,
3283 CRYPT_SIGNATURELEVEL_NONE, CRYPT_UNUSED ) )
3284 return( FALSE );
3285 fputs( "OCSPv1 succeeded.\n", outputStream );
3286 if( !printCertInfo( cryptOCSPRequest ) )
3287 return( FALSE );
3288
3289 /* Destroy the request. We can't do much more than this at this stage
3290 since the request is only used internally by the OCSP session code */
3291 status = cryptDestroyCert( cryptOCSPRequest );
3292 if( cryptStatusError( status ) )
3293 {
3294 printf( "cryptDestroyCert() failed with error code %d, line %d.\n",
3295 status, __LINE__ );
3296 return( FALSE );
3297 }
3298
3299 #if 0 /* OCSPv2 is still in too much of a state of flux to implement this */
3300 /* Try again with a v2 request. This only differs from the v1 request in
3301 the way the ID generation is handled so we don't bother printing any
3302 information on the request */
3303 if( !initOCSP( &cryptOCSPRequest, NULL, NULL, 1, TRUE, FALSE, FALSE,
3304 CRYPT_SIGNATURELEVEL_NONE, CRYPT_UNUSED ) )
3305 return( FALSE );
3306 fputs( "OCSPv2 succeeded.\n", outputStream );
3307 cryptDestroyCert( cryptOCSPRequest );
3308 #endif
3309
3310 /* Finally, create a signed request, first without and then with signing
3311 certs */
3312 status = getPrivateKey( &cryptPrivateKey, USER_PRIVKEY_FILE,
3313 USER_PRIVKEY_LABEL, TEST_PRIVKEY_PASSWORD );
3314 if( cryptStatusError( status ) )
3315 {
3316 fprintf( outputStream, "User private key read failed with error "
3317 "code %d, line %d.\n", status, __LINE__ );
3318 return( FALSE );
3319 }
3320 if( !initOCSP( &cryptOCSPRequest, NULL, NULL, 1, FALSE, FALSE, FALSE,
3321 CRYPT_SIGNATURELEVEL_NONE, cryptPrivateKey ) )
3322 return( FALSE );
3323 cryptDestroyCert( cryptOCSPRequest );
3324 fputs( "Signed OCSP request succeeded.\n", outputStream );
3325 if( !initOCSP( &cryptOCSPRequest, NULL, NULL, 1, FALSE, FALSE, FALSE,
3326 CRYPT_SIGNATURELEVEL_SIGNERCERT, cryptPrivateKey ) )
3327 return( FALSE );
3328 cryptDestroyCert( cryptOCSPRequest );
3329 fputs( "Signed OCSP request with single signing certificate "
3330 "succeeded.\n", outputStream );
3331 if( !initOCSP( &cryptOCSPRequest, NULL, NULL, 1, FALSE, FALSE, FALSE,
3332 CRYPT_SIGNATURELEVEL_ALL, cryptPrivateKey ) )
3333 return( FALSE );
3334 cryptDestroyCert( cryptOCSPRequest );
3335 fputs( "Signed OCSP request with signing certificate chain "
3336 "succeeded.\n", outputStream );
3337 cryptDestroyContext( cryptPrivateKey );
3338
3339 fputs( "OCSP request creation succeeded.\n\n", outputStream );
3340 return( TRUE );
3341 }
3342
3343 /* Test PKI user information creation. This doesn't actually test much
3344 since this object type is just a basic data container used to hold user
3345 information in a certificate store */
3346
3347 static const CERT_DATA FAR_BSS pkiUserData[] = {
3348 /* Identification information */
3349 { CRYPT_CERTINFO_COUNTRYNAME, IS_STRING, 0, TEXT( "NZ" ) },
3350 { CRYPT_CERTINFO_ORGANIZATIONNAME, IS_STRING, 0, TEXT( "Dave's Wetaburgers" ) },
3351 { CRYPT_CERTINFO_ORGANIZATIONALUNITNAME, IS_STRING, 0, TEXT( "Procurement" ) },
3352 { CRYPT_CERTINFO_COMMONNAME, IS_STRING, 0, TEXT( "Test PKI user" ) },
3353
3354 { CRYPT_ATTRIBUTE_NONE, IS_VOID }
3355 };
3356 static const CERT_DATA FAR_BSS pkiUserExtData[] = {
3357 /* Identification information */
3358 { CRYPT_CERTINFO_COUNTRYNAME, IS_STRING, 0, TEXT( "NZ" ) },
3359 { CRYPT_CERTINFO_ORGANIZATIONNAME, IS_STRING, 0, TEXT( "Dave's Wetaburgers" ) },
3360 { CRYPT_CERTINFO_ORGANIZATIONALUNITNAME, IS_STRING, 0, TEXT( "Procurement" ) },
3361 { CRYPT_CERTINFO_COMMONNAME, IS_STRING, 0, TEXT( "Test extended PKI user" ) },
3362
3363 /* SSL server and client authentication */
3364 { CRYPT_CERTINFO_EXTKEY_SERVERAUTH, IS_NUMERIC, CRYPT_UNUSED },
3365 { CRYPT_CERTINFO_EXTKEY_CLIENTAUTH, IS_NUMERIC, CRYPT_UNUSED },
3366
3367 { CRYPT_ATTRIBUTE_NONE, IS_VOID }
3368 };
3369 static const CERT_DATA FAR_BSS pkiUserCAData[] = {
3370 /* Identification information */
3371 { CRYPT_CERTINFO_COUNTRYNAME, IS_STRING, 0, TEXT( "NZ" ) },
3372 { CRYPT_CERTINFO_ORGANIZATIONNAME, IS_STRING, 0, TEXT( "Dave's Wetaburgers" ) },
3373 { CRYPT_CERTINFO_ORGANIZATIONALUNITNAME, IS_STRING, 0, TEXT( "Procurement" ) },
3374 { CRYPT_CERTINFO_COMMONNAME, IS_STRING, 0, TEXT( "Test CA PKI user" ) },
3375
3376 /* CA extensions */
3377 { CRYPT_CERTINFO_KEYUSAGE, IS_NUMERIC,
3378 CRYPT_KEYUSAGE_KEYCERTSIGN | CRYPT_KEYUSAGE_CRLSIGN },
3379 { CRYPT_CERTINFO_CA, IS_NUMERIC, TRUE },
3380
3381 { CRYPT_ATTRIBUTE_NONE, IS_VOID }
3382 };
3383 static const CERT_DATA FAR_BSS pkiUserRAData[] = {
3384 /* Identification information */
3385 { CRYPT_CERTINFO_COUNTRYNAME, IS_STRING, 0, TEXT( "NZ" ) },
3386 { CRYPT_CERTINFO_ORGANIZATIONNAME, IS_STRING, 0, TEXT( "Dave's Wetaburgers" ) },
3387 { CRYPT_CERTINFO_ORGANIZATIONALUNITNAME, IS_STRING, 0, TEXT( "Procurement" ) },
3388 { CRYPT_CERTINFO_COMMONNAME, IS_STRING, 0, TEXT( "Test RA PKI user" ) },
3389
3390 /* RA flag */
3391 { CRYPT_CERTINFO_PKIUSER_RA, IS_NUMERIC, TRUE },
3392
3393 { CRYPT_ATTRIBUTE_NONE, IS_VOID }
3394 };
3395
3396 #define PKIUSER_NAME_INDEX 3 /* Index of name in CERT_DATA info */
3397
testPKIUserCreate(const CERT_DATA * pkiUserInfo)3398 static int testPKIUserCreate( const CERT_DATA *pkiUserInfo )
3399 {
3400 CRYPT_CERTIFICATE cryptPKIUser;
3401 int status;
3402
3403 /* Create the PKI user object and add the user's identification
3404 information */
3405 status = cryptCreateCert( &cryptPKIUser, CRYPT_UNUSED,
3406 CRYPT_CERTTYPE_PKIUSER );
3407 if( cryptStatusError( status ) )
3408 {
3409 fprintf( outputStream, "cryptCreateCert() failed with error "
3410 "code %d, line %d.\n", status, __LINE__ );
3411 return( FALSE );
3412 }
3413 if( !addCertFields( cryptPKIUser, pkiUserInfo, __LINE__ ) )
3414 {
3415 printf( "Couldn't create PKI user info for user '%s', line %d.\n",
3416 ( char * ) pkiUserInfo[ PKIUSER_NAME_INDEX ].stringValue,
3417 __LINE__ );
3418 return( FALSE );
3419 }
3420 cryptDestroyCert( cryptPKIUser );
3421
3422 return( TRUE );
3423 }
3424
testPKIUser(void)3425 int testPKIUser( void )
3426 {
3427 fputs( "Testing PKI user information creation...\n", outputStream );
3428 if( !testPKIUserCreate( pkiUserData ) )
3429 return( FALSE );
3430 if( !testPKIUserCreate( pkiUserExtData ) )
3431 return( FALSE );
3432 if( !testPKIUserCreate( pkiUserCAData ) )
3433 return( FALSE );
3434 if( !testPKIUserCreate( pkiUserRAData ) )
3435 return( FALSE );
3436 fputs( "PKI user information creation succeeded.\n\n", outputStream );
3437 return( TRUE );
3438 }
3439