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