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