cryptlib  3.4.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros
s_cmp.c
Go to the documentation of this file.
1 /****************************************************************************
2 * *
3 * cryptlib CMP Session Test Routines *
4 * Copyright Peter Gutmann 1998-2009 *
5 * *
6 ****************************************************************************/
7 
8 #include "cryptlib.h"
9 #include "test/test.h"
10 
11 #if defined( __MVS__ ) || defined( __VMCMS__ )
12  /* Suspend conversion of literals to ASCII. */
13  #pragma convlit( suspend )
14 #endif /* IBM big iron */
15 #if defined( __ILEC400__ )
16  #pragma convert( 0 )
17 #endif /* IBM medium iron */
18 
19 /* If we're running the test with a crypto device, we have to set an extended
20  timeout because of the long time it takes many devices to generate keys */
21 
22 #define NET_TIMEOUT 180
23 
24 #if defined( TEST_SESSION ) || defined( TEST_SESSION_LOOPBACK )
25 
26 /****************************************************************************
27 * *
28 * CMP Test Data *
29 * *
30 ****************************************************************************/
31 
32 /* There are various CMP test CAs available, the following mappings can be
33  used to test different ones. Implementation peculiarities:
34 
35  #1 - cryptlib: Implicitly revokes certificate being replaced during a
36  kur (this is a requirement for maintaining certificate store
37  consistency).
38  Tested: ir, cr/kur, rr
39  #2 - cryptlib with PKIBoot/PnP PKI functionality, otherwise as for #1.
40  #3 - Certicom: Requires signature for revocation rather than MAC,
41  requires that all certs created after the ir one have the same
42  DN as the ir certificate.
43  Tested: ir, cr/kur, rr
44  #4 - ssh old: None (recently re-issued their CA certificate which is
45  broken, CA couldn't be re-tested. In addition since CMP
46  identifies the sender by DN the new certificate can't be
47  distinguished from the old one, causing all sig checks to
48  fail).
49  Tested (late 2000): ir, cr/kur, rr
50  #5 - ssh new:
51  #6 - Entrust: Won't allow altNames, changes sender and request DN,
52  returns rejected response under an altered DN belonging to a
53  completely different EE for anything but ir.
54  Tested: ir
55  #7 - Trustcenter: Requires HTTPS and pre-existing trusted private key
56  distributed as PKCS #12 file, couldn't be tested.
57  #8 - Baltimore: Server unavailable for testing.
58  Tested: -
59  #9 - Initech: Needs DN cn=CryptLIB EE 1,o=INITECH,c=KR.
60  Tested: ir, cr/kur, rr
61  #10 - RSA labs: Rejects signed requests, couldn't be tested beyond initial
62  (MACd) ir. Attempt to revoke newly-issued certificate with MACd
63  rr returns error indicating that the certificate is already
64  revoked.
65  Tested: ir
66  #11 - Cylink: Invalid CA root certificate, requires use of DN from RA
67  rather than CA when communicating with server.
68  Tested: -
69  #12 - Insta-Certifier: Returned garbled bits of the "tcp" protocol
70  header in earlier versions, later versions improved somewhat,
71  however a kur is rejected with the message "CRMF did not contain
72  oldCertId control". Information at
73  http://www.certificate.fi/resources/demos/demo.htm.
74  Tested: ir, cr */
75 
76 #define CA_CRYPTLIB 1
77 #define CA_CRYPTLIB_PNPPKI 2
78 
79 #define CA_NO CA_CRYPTLIB
80 
81 typedef struct {
82  const char FAR_BSS *name;
83  const C_CHR FAR_BSS *url, FAR_BSS *user, FAR_BSS *password;
84  } CA_INFO;
85 
86 static const CA_INFO FAR_BSS caInfoTbl[] = {
87  { NULL }, /* Dummy so index == CA_NO */
88  { /*1*/ "cryptlib", TEXT( "http://localhost" ), TEXT( "interop" ), TEXT( "interop" ) },
89  { /*2*/ "cryptlib/PKIBoot", /*"_pkiboot._tcp.cryptoapps.com"*/TEXT( "http://localhost" ), TEXT( "interop" ), TEXT( "interop" ) },
90  { /*3*/ "Certicom", TEXT( "cmp://gandalf.trustpoint.com:8081" ), TEXT( "interop" ), TEXT( "interop" ) },
91  { /*4*/ "ssh", TEXT( "cmp://interop-ca.ssh.com:8290" ), TEXT( "123456" ), TEXT( "interop" ) },
92  { /*5*/ "ssh", TEXT( "http://pki.ssh.com:8080/pkix/" ), TEXT( "62154" ), TEXT( "ssh" ) },
93  { /*6*/ "Entrust", TEXT( "cmp://204.101.128.45:829" ), TEXT( "39141091" ), TEXT( "ABCDEFGHIJK" ) },
94  { /*7*/ "Trustcenter", TEXT( "cmp://demo.trustcenter.de/cgi-bin/cmp:829" ), TEXT( "interop" ), TEXT( "interop" ) },
95  { /*8*/ "Baltimore", TEXT( "cmp://hip.baltimore.ie:8290" ), TEXT( "pgutmann" ), TEXT( "the-magical-land-near-oz" ) },
96  { /*9*/ "Initech", TEXT( "cmp://61.74.133.49:8290" ), TEXT( "interop" ), TEXT( "interop" ) },
97  { /*A*/ "RSA", TEXT( "cmp://ca1.kcspilot.com:32829" ), TEXT( "interop" ), TEXT( "interop" ) },
98  { /*B*/ "Cylink", TEXT( "cmp://216.252.217.227:8082" ), TEXT( "3986" ), TEXT( "11002" ) /* "3987", "6711" */ },
99  { /*C*/ "Insta-Certifier", TEXT( "http://pki.certificate.fi:8700/pkix/" ), TEXT( "3078" ), TEXT( "insta" ) }
100  };
101 
102 /* Enable additional tests if we're using cryptlib as the server */
103 
104 #if ( CA_NO == CA_CRYPTLIB ) || ( CA_NO == CA_CRYPTLIB_PNPPKI )
105  #define SERVER_IS_CRYPTLIB
106 #endif /* Extra tests for cryptib CA */
107 
108 /* Define the following to work around CA bugs/quirks */
109 
110 #if ( CA_NO == 3 ) /* Certicom */
111  #define SERVER_IR_DN
112 #endif /* CA that requires same DN in cr as ir */
113 #if ( CA_NO == 6 ) /* Entrust */
114  #define SERVER_NO_ALTNAMES
115 #endif /* CAs that won't allow altNames in requests */
116 #if ( CA_NO == 9 ) /* Initech */
117  #define SERVER_FIXED_DN
118 #endif /* CAs that require a fixed DN in requests */
119 
120 /* The following defines can be used to selectively enable or disable some
121  of the test (for example to do an ir + rr, or ir + kur + rr) */
122 
123 #ifdef SERVER_IS_CRYPTLIB
124  #define TEST_IR_NODN
125  #define TEST_IR
126 /*#define TEST_DUP_IR */
127  #define TEST_KUR
128  #define TEST_CR
129  #define TEST_RR
130 
131  /* 4 certificate reqs (two ir variants), 1 rev.req (kur = impl.rev).
132 
133  The duplicate-ir check is currently disabled because it's enforced via
134  database transaction constraints, which means that once the initial ir
135  has been recorded all further issue operations with the same ID are
136  excluded by the presence of the ID for the ir. This is a strong
137  guarantee that subsequent requests with the same ID will be disallowed,
138  but not terribly useful for self-test purposes */
139  #define NO_CA_REQUESTS ( 5 + 0 )
140 #else
141  #define TEST_IR
142  #define TEST_KUR
143  #define TEST_CR
144  #define TEST_RR
145 
146  /* Loopback test requires SERVER_IS_CRYPTLIB */
147  #define NO_CA_REQUESTS 0
148 #endif /* SERVER_IS_CRYPTLIB */
149 
150 /* Define the following to enable testing of servers where the initial DN
151  (and optional additional information like the altName) is supplied by the
152  server (i.e. the user supplies a null DN) */
153 
154 #ifdef SERVER_IS_CRYPTLIB
155  #define SERVER_PROVIDES_DN
156 #endif /* CAs where the server provides the DN */
157 
158 /* PKI user data to authorise the issuing of the various certificates */
159 
160 static const CERT_DATA FAR_BSS cmpPkiUserFullDNData[] = {
161  /* Identification information */
162  { CRYPT_CERTINFO_COUNTRYNAME, IS_STRING, 0, TEXT( "NZ" ) },
163  { CRYPT_CERTINFO_ORGANIZATIONNAME, IS_STRING, 0, TEXT( "Dave's Wetaburgers" ) },
164  { CRYPT_CERTINFO_ORGANIZATIONALUNITNAME, IS_STRING, 0, TEXT( "Procurement" ) },
165  { CRYPT_CERTINFO_COMMONNAME, IS_STRING, 0, TEXT( "Test PKI user" ) },
166 
167  /* Subject altName */
169 
171  };
172 static const CERT_DATA FAR_BSS cmpPkiUserPartialDNData[] = {
173  /* Identification information */
174  { CRYPT_CERTINFO_COUNTRYNAME, IS_STRING, 0, TEXT( "NZ" ) },
175  { CRYPT_CERTINFO_ORGANIZATIONNAME, IS_STRING, 0, TEXT( "Dave's Wetaburgers" ) },
176  { CRYPT_CERTINFO_ORGANIZATIONALUNITNAME, IS_STRING, 0, TEXT( "Procurement" ) },
177 
179  };
180 static const CERT_DATA FAR_BSS cmpPkiUserCaData[] = {
181  /* Identification information */
182  { CRYPT_CERTINFO_COUNTRYNAME, IS_STRING, 0, TEXT( "NZ" ) },
183  { CRYPT_CERTINFO_ORGANIZATIONNAME, IS_STRING, 0, TEXT( "Dave's Wetaburgers" ) },
184  { CRYPT_CERTINFO_ORGANIZATIONALUNITNAME, IS_STRING, 0, TEXT( "Procurement" ) },
185  { CRYPT_CERTINFO_COMMONNAME, IS_STRING, 0, TEXT( "Test CA PKI user" ) },
186 
187  /* Subject altName */
189 
190  /* CA extensions */
194 
196  };
197 
198 /* Certificate request data for the various types of certificates that the
199  cryptlib CMP CA can return */
200 
201 static const CERT_DATA FAR_BSS cmpCryptlibRequestNoDNData[] = { /* For ir */
202  /* Identification information - none, it's provided by the server */
203 
204  /* Subject altName - none, it's provided by the server */
205 
206  /* Signature-only key */
208 
210  };
211 static const CERT_DATA FAR_BSS cmpCryptlibRequestData[] = { /* For cr */
212  /* Identification information. The rest of the DN is provided by the
213  CA. Note that the ability to handle full DNs in the request is
214  tested by the kur, whose contents aren't defined here since they're
215  taken from the certificate being updated */
216  { CRYPT_CERTINFO_COMMONNAME, IS_STRING, 0, TEXT( "Dave's Signature Key" ) },
217 
218  /* Subject altName. The email address is provided by the CA */
219  { CRYPT_CERTINFO_UNIFORMRESOURCEIDENTIFIER, IS_STRING, 0, TEXT( "http://www.wetas-r-us.com" ) },
220 
221  /* Signature-only key */
223 
225  };
226 static const CERT_DATA FAR_BSS cmpCryptlibDsaRequestData[] = { /* Unused */
227  /* Identification information */
228  { CRYPT_CERTINFO_COUNTRYNAME, IS_STRING, 0, TEXT( "NZ" ) },
229  { CRYPT_CERTINFO_ORGANIZATIONNAME, IS_STRING, 0, TEXT( "Dave's Wetaburgers" ) },
230  { CRYPT_CERTINFO_ORGANIZATIONALUNITNAME, IS_STRING, 0, TEXT( "Procurement" ) },
231  { CRYPT_CERTINFO_COMMONNAME, IS_STRING, 0, TEXT( "Dave's DSA Key" ) },
232 
233  /* Subject altName */
235  { CRYPT_CERTINFO_UNIFORMRESOURCEIDENTIFIER, IS_STRING, 0, TEXT( "http://www.wetas-r-us.com" ) },
236 
238  };
239 
240 /* Certificate request data for the various types of certs that a CMP CA can
241  return */
242 
243 static const CERT_DATA FAR_BSS cmpRsaSignRequestData[] = { /* For cr */
244  /* Identification information */
245  #ifdef SERVER_FIXED_DN
246  { CRYPT_CERTINFO_COUNTRYNAME, IS_STRING, 0, TEXT( "KR" ) },
247  { CRYPT_CERTINFO_ORGANIZATIONNAME, IS_STRING, 0, TEXT( "INITECH" ) },
248  { CRYPT_CERTINFO_COMMONNAME, IS_STRING, 0, TEXT( "CryptLIB EE 1" ) },
249  #else
250  { CRYPT_CERTINFO_COUNTRYNAME, IS_STRING, 0, TEXT( "NZ" ) },
251  { CRYPT_CERTINFO_ORGANIZATIONNAME, IS_STRING, 0, TEXT( "Dave's Wetaburgers" ) },
252  { CRYPT_CERTINFO_ORGANIZATIONALUNITNAME, IS_STRING, 0, TEXT( "Procurement" ) },
253  { CRYPT_CERTINFO_COMMONNAME, IS_STRING, 0, TEXT( "Dave's Signature Key" ) },
254  #endif /* CAs that require a fixed DN in requests */
255 
256  /* Subject altName */
257 #ifndef SERVER_NO_ALTNAMES
259  { CRYPT_CERTINFO_UNIFORMRESOURCEIDENTIFIER, IS_STRING, 0, TEXT( "http://www.wetas-r-us.com" ) },
260 #endif /* CAs that won't allow altNames in requests */
261 
262  /* Signature-only key */
264 
266  };
267 static const CERT_DATA FAR_BSS cmpRsaEncryptRequestData[] = { /* Unused */
268  /* Identification information */
269 #ifdef SERVER_FIXED_DN
270  { CRYPT_CERTINFO_COUNTRYNAME, IS_STRING, 0, TEXT( "KR" ) },
271  { CRYPT_CERTINFO_ORGANIZATIONNAME, IS_STRING, 0, TEXT( "INITECH" ) },
272  { CRYPT_CERTINFO_COMMONNAME, IS_STRING, 0, TEXT( "CryptLIB EE 1" ) },
273 #else
274  { CRYPT_CERTINFO_COUNTRYNAME, IS_STRING, 0, TEXT( "NZ" ) },
275  { CRYPT_CERTINFO_ORGANIZATIONNAME, IS_STRING, 0, TEXT( "Dave's Wetaburgers" ) },
276  { CRYPT_CERTINFO_ORGANIZATIONALUNITNAME, IS_STRING, 0, TEXT( "Procurement" ) },
277  { CRYPT_CERTINFO_COMMONNAME, IS_STRING, 0, TEXT( "Dave's Encryption Key" ) },
278 #endif /* CAs that require a fixed DN in requests */
279 
280  /* Subject altName */
281 #ifndef SERVER_NO_ALTNAMES
283  { CRYPT_CERTINFO_UNIFORMRESOURCEIDENTIFIER, IS_STRING, 0, TEXT( "http://www.wetas-r-us.com" ) },
284 #endif /* CAs that won't allow altNames in requests */
285 
286  /* Encryption-only key */
288 
290  };
291 static const CERT_DATA FAR_BSS cmpRsaCaRequestData[] = { /* For ir-CA */
292  /* Identification information */
293  { CRYPT_CERTINFO_COUNTRYNAME, IS_STRING, 0, TEXT( "NZ" ) },
294  { CRYPT_CERTINFO_ORGANIZATIONNAME, IS_STRING, 0, TEXT( "Dave's Wetaburgers" ) },
295  { CRYPT_CERTINFO_ORGANIZATIONALUNITNAME, IS_STRING, 0, TEXT( "Procurement" ) },
296  { CRYPT_CERTINFO_COMMONNAME, IS_STRING, 0, TEXT( "Dave's Intermediate CA Key" ) },
297 
298  /* Subject altName */
300  { CRYPT_CERTINFO_UNIFORMRESOURCEIDENTIFIER, IS_STRING, 0, TEXT( "http://www.wetas-r-us.com" ) },
301 
302  /* CA key */
304 
306  };
307 
308 /****************************************************************************
309 * *
310 * Utility Functions *
311 * *
312 ****************************************************************************/
313 
314 /* Create various CMP objects */
315 
316 static int createCmpNewKeyRequest( const CERT_DATA *requestData,
318  const BOOLEAN useFixedKey,
319  const CRYPT_KEYSET cryptKeyset )
320  {
321  CRYPT_CERTIFICATE cryptRequest;
323  int status;
324 
325  /* It's a new request, generate a private key and create a self-signed
326  request */
327  if( useFixedKey )
328  {
329  /* Use a fixed private key, for testing purposes */
330  if( cryptAlgo == CRYPT_ALGO_RSA )
331  loadRSAContextsEx( CRYPT_UNUSED, NULL, &cryptContext, NULL,
333  else
334  loadDSAContextsEx( CRYPT_UNUSED, &cryptContext, NULL,
335  USER_PRIVKEY_LABEL, NULL );
336  status = CRYPT_OK;
337  }
338  else
339  {
340  status = cryptCreateContext( &cryptContext, CRYPT_UNUSED,
341  cryptAlgo );
342  if( cryptStatusError( status ) )
343  return( FALSE );
347  status = cryptGenerateKey( cryptContext );
348  }
349  if( cryptStatusOK( status ) )
350  status = cryptCreateCert( &cryptRequest, CRYPT_UNUSED,
352  if( cryptStatusOK( status ) )
353  status = cryptSetAttribute( cryptRequest,
354  CRYPT_CERTINFO_SUBJECTPUBLICKEYINFO, cryptContext );
355  if( cryptStatusOK( status ) && \
356  !addCertFields( cryptRequest, requestData, __LINE__ ) )
357  status = CRYPT_ERROR_FAILED;
358  if( cryptStatusOK( status ) )
359  status = cryptSignCert( cryptRequest, cryptContext );
360  if( cryptKeyset != CRYPT_UNUSED )
361  {
362  if( cryptStatusError( \
363  cryptAddPrivateKey( cryptKeyset, cryptContext,
365  return( FALSE );
366  }
367  cryptDestroyContext( cryptContext );
368  if( cryptStatusError( status ) )
369  {
370  printf( "Creation of CMP request failed with error code %d, line "
371  "%d.\n", status, __LINE__ );
372  return( FALSE );
373  }
374 
375  return( cryptRequest );
376  }
377 
378 static int createCmpRequest( const CERT_DATA *requestData,
379  const CRYPT_CONTEXT privateKey,
380  const CRYPT_ALGO_TYPE cryptAlgo,
381  const BOOLEAN useFixedKey,
382  const CRYPT_KEYSET cryptKeyset )
383  {
384  CRYPT_CERTIFICATE cryptRequest;
385  time_t startTime;
386  int dummy, status;
387 
388  /* If there's no existing private key available, generate a new key
389  along with the request */
390  if( privateKey == CRYPT_UNUSED )
391  return( createCmpNewKeyRequest( requestData, cryptAlgo, useFixedKey,
392  cryptKeyset ) );
393 
394  /* We're updating an existing certificate we have to vary something in
395  the request to make sure that the result doesn't duplicate an existing
396  certificate, to do this we fiddle the start time */
398  &startTime, &dummy );
399  if( cryptStatusError( status ) )
400  return( FALSE );
401  startTime++;
402 
403  /* It's an update of existing information, sign the request with the
404  given private key */
405  status = cryptCreateCert( &cryptRequest, CRYPT_UNUSED,
407  if( cryptStatusOK( status ) )
408  status = cryptSetAttribute( cryptRequest,
409  CRYPT_CERTINFO_CERTIFICATE, privateKey );
410  if( cryptStatusOK( status ) )
411  status = cryptSetAttributeString( cryptRequest,
412  CRYPT_CERTINFO_VALIDFROM, &startTime, sizeof( time_t ) );
413  if( cryptStatusOK( status ) )
414  status = cryptSignCert( cryptRequest, privateKey );
415  if( cryptKeyset != CRYPT_UNUSED )
416  {
417  if( cryptStatusError( \
418  cryptAddPrivateKey( cryptKeyset, privateKey,
420  return( FALSE );
421  }
422  if( cryptStatusError( status ) )
423  {
424  printf( "Creation of CMP request failed with error code %d, line "
425  "%d.\n", status, __LINE__ );
426  return( FALSE );
427  }
428 
429  return( cryptRequest );
430  }
431 
432 static int createCmpRevRequest( const CRYPT_CERTIFICATE cryptCert )
433  {
434  CRYPT_CERTIFICATE cryptRequest;
435  int status;
436 
437  /* Create the CMP (CRMF) revocation request */
438  status = cryptCreateCert( &cryptRequest, CRYPT_UNUSED,
440  if( cryptStatusOK( status ) )
441  status = cryptSetAttribute( cryptRequest, CRYPT_CERTINFO_CERTIFICATE,
442  cryptCert );
443  if( cryptStatusError( status ) )
444  {
445  printf( "Creation of CMP revocation request failed with error code "
446  "%d, line %d.\n", status, __LINE__ );
447  return( FALSE );
448  }
449 
450  return( cryptRequest );
451  }
452 
453 static int createCmpSession( const CRYPT_CONTEXT cryptCACert,
454  const C_STR server, const C_STR user,
455  const C_STR password,
456  const CRYPT_CONTEXT privateKey,
457  const BOOLEAN isRevocation,
458  const BOOLEAN isUpdate,
459  const BOOLEAN isPKIBoot,
460  const CRYPT_KEYSET pnpPkiKeyset )
461  {
462  CRYPT_SESSION cryptSession;
463  int status;
464 
465  assert( cryptCACert == CRYPT_UNUSED || !isPKIBoot );
466 
467  /* Create the CMP session */
468  status = cryptCreateSession( &cryptSession, CRYPT_UNUSED,
470  if( status == CRYPT_ERROR_PARAM3 ) /* CMP session access not available */
471  return( CRYPT_ERROR_NOTAVAIL );
472  if( cryptStatusError( status ) )
473  {
474  printf( "cryptCreateSession() failed with error code %d, line %d.\n",
475  status, __LINE__ );
476  return( FALSE );
477  }
478 
479  /* Set up the user and server information. Revocation requests can be
480  signed or MACd so we handle either. When requesting a certificate
481  using a signed request (i.e.not an initialisation request) we use an
482  update since we're reusing the previously-generated certificate data
483  to request a new one and some CAs won't allow this reuse for a
484  straight request but require explicit use of an update request */
485  if( privateKey != CRYPT_UNUSED )
486  {
487  status = cryptSetAttribute( cryptSession,
489  isRevocation ? \
491  isUpdate ? \
494  if( cryptStatusOK( status ) )
495  status = cryptSetAttribute( cryptSession,
497  privateKey );
498  }
499  else
500  {
501  status = cryptSetAttributeString( cryptSession,
503  paramStrlen( user ) );
504  if( cryptStatusOK( status ) )
505  status = cryptSetAttributeString( cryptSession,
506  CRYPT_SESSINFO_PASSWORD, password,
507  paramStrlen( password ) );
508  if( cryptStatusOK( status ) && pnpPkiKeyset != CRYPT_UNUSED )
509  {
510  /* PnP PKI, no request type, keyset to store returned data */
511  status = cryptSetAttribute( cryptSession,
513  pnpPkiKeyset );
514  }
515  else
516  {
517  /* Standard transaction, specify the request type */
518  status = cryptSetAttribute( cryptSession,
520  isPKIBoot ? \
522  isRevocation ? \
525  }
526  }
527  if( cryptStatusOK( status ) )
528  status = cryptSetAttributeString( cryptSession,
530  paramStrlen( server ) );
531  if( cryptStatusOK( status ) && cryptCACert != CRYPT_UNUSED )
532  status = cryptSetAttribute( cryptSession,
534  cryptCACert );
535  if( cryptStatusError( status ) )
536  {
537  printf( "Addition of session information failed with error code %d, "
538  "line %d.\n", status, __LINE__ );
539  return( FALSE );
540  }
541 
542  return( cryptSession );
543  }
544 
545 /* Request a particular certificate type */
546 
547 static int requestCert( const char *description, const CA_INFO *caInfoPtr,
548  const C_STR readKeysetName,
549  const C_STR writeKeysetName,
550  const CERT_DATA *requestData,
551  const CRYPT_ALGO_TYPE cryptAlgo,
552  const CRYPT_CONTEXT cryptCACert,
553  const BOOLEAN isPKIBoot,
554  const BOOLEAN isPnPPKI,
555  CRYPT_CERTIFICATE *issuedCert )
556  {
557  CRYPT_SESSION cryptSession;
558  CRYPT_KEYSET cryptKeyset = CRYPT_UNUSED;
559  CRYPT_CONTEXT privateKey = CRYPT_UNUSED;
560  CRYPT_CERTIFICATE cryptCmpRequest, cryptCmpResponse;
561  const BOOLEAN useExistingKey = ( requestData == NULL ) ? TRUE : FALSE;
562  BOOLEAN hasC = FALSE, hasCN = FALSE;
563  int i, status;
564 
565  assert( !isPKIBoot || !isPnPPKI );
566  assert( !( isPnPPKI && writeKeysetName == NULL ) );
567 
568  if( requestData != NULL )
569  {
570  for( i = 0; requestData[ i ].type != CRYPT_ATTRIBUTE_NONE; i++ )
571  {
572  if( requestData[ i ].type == CRYPT_CERTINFO_COUNTRYNAME )
573  hasC = TRUE;
574  if( requestData[ i ].type == CRYPT_CERTINFO_COMMONNAME )
575  hasCN = TRUE;
576  }
577  }
578  if( isPKIBoot )
579  puts( "Testing standalone PKIBoot with no certificate request" );
580  else
581  {
582  printf( "Testing %s processing", description );
583  if( requestData == NULL )
584  printf( "with implicitly-supplied subject DN" );
585  else
586  {
587  if( hasCN )
588  printf( " with partial subject DN" );
589  else
590  {
591  if( !hasC )
592  printf( " with CA-supplied subject DN" );
593  }
594  }
595  }
596  puts( "..." );
597 
598  /* Read the key needed to request a new certificate from a keyset if
599  necessary and create a keyset to save a new key to if required. We
600  have to do the write last in case the read and write keyset are the
601  same */
602  if( readKeysetName != NULL )
603  {
604  status = getPrivateKey( &privateKey, readKeysetName,
606  if( cryptStatusError( status ) )
607  {
608  printf( "Couldn't get private key to request new certificate, "
609  "status = %d, line %d.\n", status, __LINE__ );
610  return( FALSE );
611  }
612  }
613  if( writeKeysetName != NULL )
614  {
615  assert( !isPKIBoot ); /* Keyset -> PnPPKI, not just PKIBoot */
616  status = cryptKeysetOpen( &cryptKeyset, CRYPT_UNUSED,
617  CRYPT_KEYSET_FILE, writeKeysetName,
619  if( cryptStatusError( status ) )
620  {
621  printf( "Couldn't create keyset to store certificate to, "
622  "status = %d, line %d.\n", status, __LINE__ );
623  return( FALSE );
624  }
625  }
626 
627  /* Create the CMP session */
628  cryptSession = createCmpSession( cryptCACert, caInfoPtr->url,
629  caInfoPtr->user, caInfoPtr->password,
630  privateKey, FALSE, useExistingKey,
631  isPKIBoot,
632  isPnPPKI ? cryptKeyset : CRYPT_UNUSED );
633  if( cryptSession <= 0 )
634  {
635  if( cryptKeyset != CRYPT_UNUSED )
636  cryptKeysetClose( cryptKeyset );
637  return( cryptSession );
638  }
639 
640  /* Set up the request. Some CAs explicitly disallow multiple dissimilar
641  certs to exist for the same key (in fact for non-test servers other
642  CAs probably enforce this as well) but generating a new key for each
643  request is time-consuming so we only do it if it's enforced by the
644  CA */
645  if( !isPKIBoot )
646  {
647 #if defined( SERVER_IS_CRYPTLIB ) || defined( SERVER_FIXED_DN )
648  cryptCmpRequest = createCmpRequest( requestData,
649  useExistingKey ? privateKey : CRYPT_UNUSED,
650  cryptAlgo, FALSE, cryptKeyset );
651 #else
652  KLUDGE_WARN( "fixed key for request" );
653  cryptCmpRequest = createCmpRequest( requestData,
654  useExistingKey ? privateKey : CRYPT_UNUSED,
655  cryptAlgo, TRUE, cryptKeyset );
656 #endif /* cryptlib and Initech won't allow two certs for same key */
657  if( !cryptCmpRequest )
658  return( FALSE );
659  if( privateKey != CRYPT_UNUSED )
660  cryptDestroyContext( privateKey );
661  status = cryptSetAttribute( cryptSession, CRYPT_SESSINFO_REQUEST,
662  cryptCmpRequest );
663  cryptDestroyCert( cryptCmpRequest );
664  if( cryptStatusError( status ) )
665  {
666  printf( "cryptSetAttribute() failed with error code %d, line %d.\n",
667  status, __LINE__ );
668  return( FALSE );
669  }
670  }
671 
672  /* Activate the session */
673  status = cryptSetAttribute( cryptSession, CRYPT_SESSINFO_ACTIVE, TRUE );
674  if( cryptStatusError( status ) )
675  {
676  if( cryptKeyset != CRYPT_UNUSED )
677  cryptKeysetClose( cryptKeyset );
678  printExtError( cryptSession, "Attempt to activate CMP client session",
679  status, __LINE__ );
680 #ifdef SERVER_IS_CRYPTLIB
681  if( status == CRYPT_ERROR_NOTFOUND )
682  {
683  char errorMessage[ 512 ];
684  int errorMessageLength;
685 
686  /* If there's something else listening on the local port that
687  we use for CMP then it's unlikely to respond to a CMP
688  request, so we add a special-case check for this and don't
689  treat it as a fatal error */
690  status = cryptGetAttributeString( cryptSession,
692  errorMessage,
693  &errorMessageLength );
694  cryptDestroySession( cryptSession );
695  if( cryptStatusOK( status ) && \
696  errorMessageLength > 13 &&
697  !memcmp( errorMessage, "HTTP response", 13 ) )
698  {
699  puts( " (Something other than a CMP server is listening on "
700  "the local port used for\n testing, "
701  "continuing...)\n" );
702  return( CRYPT_ERROR_FAILED );
703  }
704  }
705  else
706 #endif /* SERVER_IS_CRYPTLIB */
707  cryptDestroySession( cryptSession );
708  if( status == CRYPT_ERROR_OPEN || status == CRYPT_ERROR_READ )
709  {
710  /* These servers are constantly appearing and disappearing so if
711  we get a straight connect error we don't treat it as a serious
712  failure */
713  puts( " (Server could be down, faking it and continuing...)\n" );
714  return( CRYPT_ERROR_FAILED );
715  }
716  if( status == CRYPT_ERROR_FAILED )
717  {
718  /* A general failed response is more likely to be due to the
719  server doing something unexpected than a cryptlib problem so
720  we don't treat it as a fatal error */
721  puts( " (This is more likely to be an issue with the server than "
722  "with cryptlib,\n faking it and continuing...)\n" );
723  return( CRYPT_ERROR_FAILED );
724  }
725  return( FALSE );
726  }
727 
728  /* If it's a PKIBoot, which just sets (implicitly) trusted certs, we're
729  done */
730  if( isPKIBoot )
731  {
732  cryptDestroySession( cryptSession );
733  return( TRUE );
734  }
735 
736  /* Obtain the response information */
737  status = cryptGetAttribute( cryptSession, CRYPT_SESSINFO_RESPONSE,
738  &cryptCmpResponse );
739  cryptDestroySession( cryptSession );
740  if( cryptStatusError( status ) )
741  {
742  printf( "cryptGetAttribute() failed with error code %d, line %d.\n",
743  status, __LINE__ );
744  return( FALSE );
745  }
746 #ifndef SERVER_IS_CRYPTLIB
747  puts( "Returned certificate details are:" );
748  printCertInfo( cryptCmpResponse );
749 #endif /* Keep the cryptlib results on one screen */
750  if( cryptKeyset != CRYPT_UNUSED )
751  {
752  status = cryptAddPublicKey( cryptKeyset, cryptCmpResponse );
753  if( cryptStatusError( status ) )
754  {
755  printf( "Couldn't write certificate to keyset, status = %d, "
756  "line %d.\n", status, __LINE__ );
757  return( FALSE );
758  }
759  cryptKeysetClose( cryptKeyset );
760  }
761  if( issuedCert != NULL )
762  *issuedCert = cryptCmpResponse;
763  else
764  cryptDestroyCert( cryptCmpResponse );
765 
766  /* Clean up */
767  printf( "Successfully processed %s.\n\n", description );
768  return( TRUE );
769  }
770 
771 /* Revoke a previously-issued certificate */
772 
773 static int revokeCert( const char *description, const CA_INFO *caInfoPtr,
774  const C_STR keysetName,
775  const CRYPT_CERTIFICATE certToRevoke,
776  const CRYPT_CONTEXT cryptCACert,
777  const BOOLEAN signRequest )
778  {
779  CRYPT_SESSION cryptSession;
780  CRYPT_CONTEXT privateKey = CRYPT_UNUSED;
781  CRYPT_CERTIFICATE cryptCmpRequest, cryptCert = certToRevoke;
782  int status;
783 
784  printf( "Testing %s revocation processing...\n", description );
785 
786  /* Get the certificate to revoke if necessary. In some cases the server
787  won't accept a revocation password, so we have to get the private key
788  as well to sign the request */
789  if( signRequest || cryptCert == CRYPT_UNUSED )
790  {
791  CRYPT_KEYSET cryptKeyset;
792 
793  status = cryptKeysetOpen( &cryptKeyset, CRYPT_UNUSED,
794  CRYPT_KEYSET_FILE, keysetName,
796  if( cryptStatusOK( status ) && signRequest )
797  status = getPrivateKey( &privateKey, keysetName,
800  if( cryptStatusOK( status ) && cryptCert == CRYPT_UNUSED )
801  status = cryptGetPublicKey( cryptKeyset, &cryptCert,
804  cryptKeysetClose( cryptKeyset );
805  if( cryptStatusError( status ) )
806  {
807  puts( "Couldn't fetch certificate/key to revoke.\n" );
808  return( FALSE );
809  }
810  }
811 
812  /* Create the CMP session and revocation request */
813  cryptSession = createCmpSession( cryptCACert, caInfoPtr->url,
814  caInfoPtr->user, caInfoPtr->password,
815  privateKey, TRUE, FALSE, FALSE,
816  CRYPT_UNUSED );
817  if( privateKey != CRYPT_UNUSED )
818  cryptDestroyContext( privateKey );
819  if( cryptSession <= 0 )
820  return( cryptSession );
821  cryptCmpRequest = createCmpRevRequest( cryptCert );
822  if( !cryptCmpRequest )
823  return( FALSE );
824 
825  /* Set up the request and activate the session */
826  status = cryptSetAttribute( cryptSession, CRYPT_SESSINFO_REQUEST,
827  cryptCmpRequest );
828  cryptDestroyCert( cryptCmpRequest );
829  if( cryptStatusError( status ) )
830  {
831  printf( "cryptSetAttribute() failed with error code %d, line %d.\n",
832  status, __LINE__ );
833  return( FALSE );
834  }
835  status = cryptSetAttribute( cryptSession, CRYPT_SESSINFO_ACTIVE, TRUE );
836  if( cryptStatusError( status ) )
837  {
838  printExtError( cryptSession, "Attempt to activate CMP client session",
839  status, __LINE__ );
840  cryptDestroySession( cryptSession );
841  if( cryptCert != certToRevoke )
842  cryptDestroyCert( cryptCert );
843  if( status == CRYPT_ERROR_OPEN || status == CRYPT_ERROR_READ )
844  {
845  /* These servers are constantly appearing and disappearing so if
846  we get a straight connect error we don't treat it as a serious
847  failure */
848  puts( " (Server could be down, faking it and continuing...)\n" );
849  return( CRYPT_ERROR_FAILED );
850  }
851  if( status == CRYPT_ERROR_FAILED )
852  {
853  /* A general failed response is more likely to be due to the
854  server doing something unexpected than a cryptlib problem so
855  we don't treat it as a fatal error */
856  puts( " (This is more likely to be an issue with the server than "
857  "with cryptlib,\n faking it and continuing...)\n" );
858  return( CRYPT_ERROR_FAILED );
859  }
860  return( FALSE );
861  }
862 
863  /* Clean up */
864  if( cryptCert != certToRevoke )
865  cryptDestroyCert( cryptCert );
866  cryptDestroySession( cryptSession );
867  printf( "%s processing succeeded.\n\n", description );
868  return( TRUE );
869  }
870 
871 /* Get the user name and password for a PKI user */
872 
873 static int getPkiUserInfo( const C_STR pkiUserName,
874  CA_INFO *caInfoPtr, C_STR userID, C_STR issuePW )
875  {
876  int status;
877 
878  /* cryptlib implements per-user (rather than shared interop) IDs and
879  passwords so we have to read the user ID and password information
880  before we can perform any operations */
881  status = pkiGetUserInfo( userID, issuePW, NULL, pkiUserName );
882  if( status == CRYPT_ERROR_NOTAVAIL )
883  return( status );
884  if( !status )
885  return( FALSE );
886  memcpy( caInfoPtr, &caInfoTbl[ CA_NO ], sizeof( CA_INFO ) );
887  caInfoPtr->name = "cryptlib";
888  caInfoPtr->user = userID;
889  caInfoPtr->password = issuePW;
890 
891  return( TRUE );
892  }
893 
894 /****************************************************************************
895 * *
896 * CMP Routines Test *
897 * *
898 ****************************************************************************/
899 
900 /* Test the full range of CMP functionality. This performs the following
901  tests:
902 
903  RSA sign:
904  ir + ip + reject (not performed since requires cmp.c mod)
905  ir + ip + certconf + pkiconf
906  cr + cp + certconf + pkiconf
907  kur + kup + certconf + pkiconf
908  rr + rp (of ir certificate)
909  rr + rp (of kur certificate)
910  RSA encr.:
911  ir + ip + reject (requires cmp.c mod)
912  ir + ip + certconf + pkiconf
913  rr + rp (of ir certificate)
914  DSA:
915  cr + cp + certconf + pkiconf (success implies that ir/kur/rr
916  works since they've already been tested for RSA) */
917 
918 /* Connect to a cryptlib server, for the loopback tests */
919 
920 static int connectCryptlibCMP( const BOOLEAN usePKIBoot,
921  const BOOLEAN localSession )
922  {
923  CRYPT_CERTIFICATE cryptCACert = CRYPT_UNUSED, cryptCert;
924  C_CHR readFileName[ FILENAME_BUFFER_SIZE ];
925  C_CHR writeFileName[ FILENAME_BUFFER_SIZE ];
926  CA_INFO caInfo;
927  C_CHR userID[ 64 ], issuePW[ 64 ];
928  int status;
929 
930  /* Wait for the server to finish initialising */
931  if( localSession && waitMutex() == CRYPT_ERROR_TIMEOUT )
932  {
933  printf( "Timed out waiting for server to initialise, line %d.\n",
934  __LINE__ );
935  return( FALSE );
936  }
937 
938  /* Make sure that the required user information is present. If it isn't
939  then the CA auditing will detect a request from a nonexistent user
940  and refuse to issue a certificate */
941  status = pkiGetUserInfo( NULL, NULL, NULL, TEXT( "Test PKI user" ) );
942  if( status == CRYPT_ERROR_NOTAVAIL )
943  {
944  /* Cert store operations aren't available, exit but continue with
945  other tests */
946  return( TRUE );
947  }
948  if( !status )
949  {
950  puts( "CA certificate store doesn't contain the PKI user "
951  "information needed to\nauthenticate certificate issue "
952  "operations. This is probably because the\nserver loopback "
953  "test (which initialises the certificate store) hasn't been "
954  "run yet.\nSkipping CMP test.\n" );
955  return( CRYPT_ERROR_NOTAVAIL );
956  }
957 
958  /* If we're not doing PKIBoot (which obtains the CA's certificate during
959  the PKIBoot process), get the certificate of the CA who will issue
960  the certificate */
961  if( !usePKIBoot )
962  {
963  status = importCertFromTemplate( &cryptCACert, CMP_CA_FILE_TEMPLATE,
964  CA_NO );
965  if( cryptStatusError( status ) )
966  {
967  printf( "Couldn't get cryptlib CMP CA certificate, status = %d, "
968  "line %d.\n", status, __LINE__ );
969  return( FALSE );
970  }
971  }
972 
973  /* Initialisation request. We perform two ir's, the first with the CA
974  supplying the full user DN and email address, the second with the CA
975  supplying a partial DN and no email address, and the user filling in
976  the rest. We continue with the certificate from the second ir,
977  because the first one doesn't allow anything other than a kur since
978  the DN is fixed */
979  status = getPkiUserInfo( TEXT( "Test PKI user" ), &caInfo,
980  userID, issuePW );
981  if( status != TRUE )
982  {
983  if( !usePKIBoot )
984  cryptDestroyCert( cryptCACert );
985  return( FALSE );
986  }
988  status = requestCert( "certificate init.request (ir)", &caInfo, NULL,
989  usePKIBoot ? NULL : writeFileName,
990  cmpCryptlibRequestNoDNData, CRYPT_ALGO_RSA,
991  cryptCACert, usePKIBoot, FALSE, NULL );
992  if( status != TRUE )
993  {
994  /* If this is the self-test and there's a non-fatal error, make sure
995  we don't fail with a CRYPT_ERROR_INCOMPLETE when we're finished */
996  if( !usePKIBoot )
997  cryptDestroyCert( cryptCACert );
998  return( status );
999  }
1000  if( usePKIBoot )
1001  {
1002  /* If we're testing the PKIBoot capability there's only a single
1003  request to process and we're done */
1004  return( TRUE );
1005  }
1006  delayThread( 2 ); /* Wait for server to recycle */
1007  status = getPkiUserInfo( TEXT( "Procurement" ), &caInfo, userID,
1008  issuePW );
1009  if( status != TRUE )
1010  {
1011  if( !usePKIBoot )
1012  cryptDestroyCert( cryptCACert );
1013  return( FALSE );
1014  }
1016  status = requestCert( "certificate init.request (ir)", &caInfo, NULL,
1017  usePKIBoot ? NULL : writeFileName,
1018  cmpCryptlibRequestData, CRYPT_ALGO_RSA,
1019  cryptCACert, FALSE, FALSE, &cryptCert );
1020  if( status != TRUE )
1021  return( FALSE );
1022 #ifdef TEST_DUP_IR
1023  /* Attempt a second ir using the same PKI user data. This should fail,
1024  since the certificate store only allows a single ir per user */
1025  if( requestCert( "Duplicate init.request", &caInfo, NULL, NULL,
1026  cmpCryptlibRequestNoDNData, CRYPT_ALGO_RSA,
1027  cryptCACert, FALSE, TRUE, NULL ) )
1028  {
1029  printf( "Duplicate init request wasn't detected by the CMP server, "
1030  "line %d.\n\n", __LINE__ );
1031  cryptDestroyCert( cryptCACert );
1032  return( FALSE );
1033  }
1034 #endif /* TEST_DUP_IR */
1035 
1036  /* Certificate request. We have to perform this test before the kur
1037  because cryptlib implicitly revokes the certificate being replaced,
1038  which means that we can't use it to authenticate requests any more
1039  once the kur has been performed */
1042  status = requestCert( "certificate request (cr)", &caInfo, readFileName,
1043  writeFileName, cmpCryptlibRequestData,
1044  CRYPT_ALGO_RSA, cryptCACert, FALSE, FALSE, NULL );
1045  if( status != TRUE )
1046  {
1047  cryptDestroyCert( cryptCert );
1048  cryptDestroyCert( cryptCACert );
1049  return( status );
1050  }
1051  delayThread( 2 ); /* Wait for server to recycle */
1052 
1053  /* Key update request. This updates the existing key that we've just
1054  written to a file, so there's no new certificate-request data that
1055  gets submitted. In other words the new certificate that's issued is
1056  identical to the existing one except for the date/time value.
1057 
1058  Since we've just created the certificate, we have to delete it so
1059  that we can replace it with the kur'd form */
1060  cryptDestroyCert( cryptCert );
1061 
1062  /* If it's a CA that implicitly revokes the certificate being replaced
1063  (in which case tracking things gets a bit too complicated since we
1064  now need to use the updated rather than original certificate to
1065  authenticate the request) we just leave it unrevoked (the first
1066  certificate is always revoked) */
1068  status = requestCert( "certificate update (kur)", &caInfo, readFileName,
1069  NULL, NULL, CRYPT_UNUSED, cryptCACert, FALSE,
1070  FALSE, &cryptCert );
1071  if( status != TRUE )
1072  {
1073  cryptDestroyCert( cryptCACert );
1074  return( status );
1075  }
1076  delayThread( 2 ); /* Wait for server to recycle */
1077 #if 0
1078  /* DSA certificate request. We have to get this now because we're about
1079  to revoke the certificate we're using to sign the requests. This
1080  currently isn't checked since it's a standard signature-only
1081  certificate request whose processing has already been checked in
1082  testCertProcess() */
1084  status = requestCert( "DSA certificate", &caInfo, readFileName, NULL,
1085  cmpDsaRequestData, CRYPT_ALGO_DSA, cryptCACert,
1086  FALSE, FALSE, NULL );
1087  if( status != TRUE )
1088  return( status );
1089  delayThread( 2 ); /* Wait for server to recycle */
1090 #endif /* 0 */
1091 
1092  /* Revocation request. The current certificate is a kur'd certificate
1093  for which the original has been implicitly revoked by the kur process
1094  and what we have now is an ephemeral test-only certificate whose
1095  details weren't stored (so they can't be passed to requestCert(), we
1096  can't do much else with it */
1097  cryptDestroyCert( cryptCert );
1098 
1099  /* We requested a second certificate whose details were recorded, revoke
1100  that. Note that we have to sign this with the second certificate
1101  since the first one was the implicitly-revoked kur'd one */
1103  status = revokeCert( "RSA signing certificate", &caInfo, readFileName,
1104  CRYPT_UNUSED, cryptCACert, TRUE );
1105  if( status != TRUE )
1106  {
1107  cryptDestroyCert( cryptCACert );
1108  return( status );
1109  }
1110 
1111  /* Clean up */
1112  cryptDestroyCert( cryptCACert );
1113  return( TRUE );
1114  }
1115 
1116 /* Connect to a non-cryptlib CMP server */
1117 
1118 static int connectCMP( void )
1119  {
1120  CRYPT_CERTIFICATE cryptCACert = CRYPT_UNUSED, cryptCert;
1121  C_CHR readFileName[ FILENAME_BUFFER_SIZE ];
1122  C_CHR writeFileName[ FILENAME_BUFFER_SIZE ];
1123  const CA_INFO *caInfoPtr = &caInfoTbl[ CA_NO ];
1124  int status;
1125 
1126  /* Get the certificate of the CA who will issue the certificate */
1127  status = importCertFromTemplate( &cryptCACert, CMP_CA_FILE_TEMPLATE,
1128  CA_NO );
1129  if( cryptStatusError( status ) )
1130  {
1131  printf( "Couldn't get CMP CA certificate, status = %d, line %d.\n",
1132  status, __LINE__ );
1133  return( FALSE );
1134  }
1135 
1136  /* Test each certificate request type */
1137 
1138 #ifdef TEST_IR
1139  /* Initialisation request. We define REVOKE_FIRST_CERT to indicate that
1140  we can revoke this one later on */
1141  #define REVOKE_FIRST_CERT
1143  status = requestCert( "certificate init.request (ir)", caInfoPtr, NULL,
1144  writeFileName, cmpRsaSignRequestData,
1145  CRYPT_ALGO_RSA, cryptCACert, FALSE, FALSE,
1146  &cryptCert );
1147  if( status != TRUE )
1148  {
1149  /* If this is the self-test and there's a non-fatal error, make sure
1150  we don't fail with a CRYPT_ERROR_INCOMPLETE when we're finished */
1151  cryptDestroyCert( cryptCACert );
1152  return( status );
1153  }
1154 #endif /* TEST_IR */
1155 
1156 #ifdef TEST_CR
1157  /* Certificate request. We have to perform this test before the kur
1158  since some CAs implicitly revoke the certificate being replaced,
1159  which means that we can't use it to authenticate requests any more
1160  once the kur has been performed. We define REVOKE_SECOND_CERT to
1161  indicate that we can revoke this one later on alongside the ir/kur'd
1162  certificate, and save a copy to a file for later use */
1163  #define REVOKE_SECOND_CERT
1166  status = requestCert( "certificate request (cr)", caInfoPtr,
1167  readFileName, writeFileName, cmpRsaSignRequestData,
1168  CRYPT_ALGO_RSA, cryptCACert, FALSE, FALSE, NULL );
1169  if( status != TRUE )
1170  {
1171  #if defined( TEST_IR )
1172  cryptDestroyCert( cryptCert );
1173  #endif /* TEST_IR || TEST_KUR */
1174  cryptDestroyCert( cryptCACert );
1175  return( status );
1176  }
1177 #endif /* TEST_CR */
1178 
1179 #ifdef TEST_KUR
1180  /* Key update request. This updates the existing key that we've just
1181  written to a file, so there's no new certificate-request data that
1182  gets submitted. In other words the new certificate that's issued is
1183  identical to the existing one except for the dates/time values */
1184  #ifdef TEST_IR
1185  /* We just created the certificate, delete it so we can replace it with
1186  the updated form */
1187  cryptDestroyCert( cryptCert );
1188  #endif /* TEST_IR */
1189 
1190  /* If it's a CA that implicitly revokes the certificate being replaced
1191  (in which case tracking things gets a bit too complicated since we
1192  now need to use the updated rather than original certificate to
1193  authenticate the request) we just leave it unrevoked (the first
1194  certificate is always revoked) */
1196  status = requestCert( "certificate update (kur)", caInfoPtr,
1197  readFileName, NULL, NULL, CRYPT_UNUSED,
1198  cryptCACert, FALSE, FALSE, &cryptCert );
1199  if( status != TRUE )
1200  {
1201  cryptDestroyCert( cryptCACert );
1202  return( status );
1203  }
1204 #endif /* TEST_KUR */
1205 #if 0
1206  /* Encryption-only certificate request. This test requires a change in
1207  certsign.c because when creating a certificate request cryptlib
1208  always allows signing for the request even if it's an encryption-only
1209  key (this is required for PKCS #10, see the comment in the kernel
1210  code). Because of this a request will always appear to be associated
1211  with a signature-enabled key so it's necessary to make a code change
1212  to disallow this. Disallowing sigs for encryption-only keys would
1213  break PKCS #10 since it's then no longer possible to create the self-
1214  signed request, this is a much bigger concern than CMP. Note that
1215  this functionality is tested by the PnP PKI test, which creates the
1216  necessary encryption-only requests internally and can do things that
1217  we can't do from the outside */
1218  status = requestCert( "encryption-only certificate", caInfoPtr,
1219  readFileName, writeFileName,
1220  cmpRsaEncryptRequestData, CRYPT_ALGO_RSA,
1221  cryptCACert, FALSE, FALSE, NULL );
1222  if( status != TRUE )
1223  return( status );
1224 #endif /* 0 */
1225 
1226  /* Revocation request */
1227 #ifdef TEST_RR
1229  #ifdef REVOKE_FIRST_CERT
1230  #ifdef SERVER_IR_DN
1231  status = revokeCert( "RSA initial/updated certificate", caInfoPtr,
1232  readFileName, cryptCert, cryptCACert, TRUE );
1233  #else
1234  status = revokeCert( "RSA initial/updated certificate", caInfoPtr,
1235  readFileName, cryptCert, cryptCACert, FALSE );
1236  #endif /* Certicom requires signed request */
1237  cryptDestroyCert( cryptCert );
1238  #elif !defined( TEST_KUR )
1239  /* We didn't issue the first certificate in this run, try revoking it
1240  from the certificate stored in the key file unless we're talking to a
1241  CA that implicitly revokes the certificate being replaced during a
1242  kur */
1243  status = revokeCert( "RSA initial/updated certificate", caInfoPtr,
1244  readFileName, CRYPT_UNUSED, cryptCACert, TRUE );
1245  #else
1246  /* This is a kur'd certificate for which the original has been
1247  implicitly revoked, we can't do much else with it */
1248  cryptDestroyCert( cryptCert );
1249  #endif /* REVOKE_FIRST_CERT */
1250  if( status != TRUE )
1251  {
1252  cryptDestroyCert( cryptCACert );
1253  return( status );
1254  }
1255  #ifdef REVOKE_SECOND_CERT
1256  /* We requested a second certificate, revoke that too. Note that we
1257  have to sign this with the second certificate since the first one may
1258  have just been revoked */
1260  status = revokeCert( "RSA signing certificate", caInfoPtr, readFileName,
1261  CRYPT_UNUSED, cryptCACert, TRUE );
1262  if( status != TRUE )
1263  {
1264  cryptDestroyCert( cryptCACert );
1265  return( status );
1266  }
1267  #endif /* REVOKE_SECOND_CERT */
1268 #endif /* TEST_RR */
1269 
1270  /* Clean up */
1271  cryptDestroyCert( cryptCACert );
1272  return( TRUE );
1273  }
1274 
1275 static int connectCMPFail( const int count )
1276  {
1277  static const CERT_DATA FAR_BSS cmpFailRequestData1[] = {
1278  /* Fails when tested against the full-DN PKI user because the CN
1279  doesn't match the PKI user CN */
1280  { CRYPT_CERTINFO_COUNTRYNAME, IS_STRING, 0, TEXT( "NZ" ) },
1281  { CRYPT_CERTINFO_ORGANIZATIONNAME, IS_STRING, 0, TEXT( "Dave's Wetaburgers" ) },
1282  { CRYPT_CERTINFO_ORGANIZATIONALUNITNAME, IS_STRING, 0, TEXT( "Procurement" ) },
1283  { CRYPT_CERTINFO_COMMONNAME, IS_STRING, 0, TEXT( "Not the test PKI user" ) },
1284 
1286  };
1287  static const CERT_DATA FAR_BSS cmpFailRequestData2[] = {
1288  /* Fails when tested against the full-DN PKI user because there's
1289  already an email address present in the PKI user data */
1290 #if 0
1292 #endif /* 0 */
1293  { CRYPT_CERTINFO_UNIFORMRESOURCEIDENTIFIER, IS_STRING, 0, TEXT( "http://www.wetas-r-us.com" ) },
1294 
1296  };
1297  static const CERT_DATA FAR_BSS cmpFailRequestData3[] = {
1298  /* Fails when tested against the partial-DN (no CN specified) PKI
1299  user because the OU doesn't match the PKI user OU even though the
1300  CN is allowed */
1301  { CRYPT_CERTINFO_ORGANIZATIONALUNITNAME, IS_STRING, 0, TEXT( "Not procurement" ) },
1302  { CRYPT_CERTINFO_COMMONNAME, IS_STRING, 0, TEXT( "Test PKI user" ) },
1303 
1305  };
1306  static const CERT_DATA FAR_BSS *cmpFailRequestDataTbl[] = {
1307  cmpFailRequestData1, cmpFailRequestData2, cmpFailRequestData3
1308  };
1309  static const C_STR FAR_BSS cmpFailRequestNameTbl[] = {
1310  TEXT( "Test PKI user" ), /* Template has full DN + email */
1311  TEXT( "Test PKI user" ), /* Template has full DN + email */
1312  TEXT( "Procurement" ) /* Template has no CN or email */
1313  };
1314  static const char *cmpFailRequestDescriptionTbl[] = {
1315  "request containing full DN with CN mis-matching\n pkiUser CN",
1316  "request containing extra field in altName\n not present in pkiUser altName",
1317  "request containing partial DN with OU\n mis-matching pkiUser CN"
1318  };
1319  CRYPT_CERTIFICATE cryptCACert = CRYPT_UNUSED, cryptCert;
1320  C_CHR writeFileName[ FILENAME_BUFFER_SIZE ];
1321  CA_INFO caInfo;
1322  C_CHR userID[ 64 ], issuePW[ 64 ];
1323  char message[ 128 ];
1324  int status;
1325 
1326  /* Wait for the server to finish initialising */
1327  if( count == 0 && waitMutex() == CRYPT_ERROR_TIMEOUT )
1328  {
1329  printf( "Timed out waiting for server to initialise, line %d.\n",
1330  __LINE__ );
1331  return( FALSE );
1332  }
1333 
1334  /* Get the certificate of the CA who will issue the certificate and the
1335  PKI user details */
1336  status = importCertFromTemplate( &cryptCACert, CMP_CA_FILE_TEMPLATE,
1337  CA_CRYPTLIB );
1338  if( cryptStatusError( status ) )
1339  {
1340  printf( "Couldn't get CMP CA certificate, status = %d, line %d.\n",
1341  status, __LINE__ );
1342  return( FALSE );
1343  }
1344  status = getPkiUserInfo( TEXT( "Test PKI user" ), &caInfo,
1345  userID, issuePW );
1346  if( status != TRUE )
1347  {
1348  cryptDestroyCert( cryptCACert );
1349  return( FALSE );
1350  }
1351 
1352  /* Send the request, which should be rejected by the server because
1353  something in the request differs from what's in the PKI user
1354  template */
1356  sprintf( message, "invalid request %d with %s,", count + 1,
1357  cmpFailRequestDescriptionTbl[ count ] );
1358  status = requestCert( message, &caInfo, NULL, NULL,
1359  cmpFailRequestDataTbl[ count ], CRYPT_ALGO_RSA,
1360  cryptCACert, FALSE, FALSE, &cryptCert );
1361  cryptDestroyCert( cryptCACert );
1362  if( status )
1363  {
1364  /* The request should have been rejected */
1365  puts( "Invalid CMP request should have been rejected, but "
1366  "wasn't.\n" );
1367  return( FALSE );
1368  }
1369 
1370  /* The request was successfully rejected, let the user know that the
1371  error spew was supposed to be there */
1372  puts( " (This isn't an error since we're checking for the rejection "
1373  "of invalid\n requests)." );
1374  return( TRUE );
1375  }
1376 
1377 int testSessionCMP( void )
1378  {
1379  return( connectCMP() );
1380  }
1381 
1382 /* Test the plug-and-play PKI functionality */
1383 
1384 static int connectPNPPKI( const BOOLEAN isCaUser, const BOOLEAN useDevice,
1385  const BOOLEAN localSession )
1386  {
1387  CRYPT_SESSION cryptSession;
1388  CRYPT_KEYSET cryptKeyset;
1389  C_CHR userID[ 64 ], issuePW[ 64 ];
1390  int status;
1391 
1392  /* Create the CMP session */
1393  status = cryptCreateSession( &cryptSession, CRYPT_UNUSED,
1395  if( status == CRYPT_ERROR_PARAM3 ) /* CMP session access not available */
1396  return( CRYPT_ERROR_NOTAVAIL );
1397  if( cryptStatusError( status ) )
1398  {
1399  printf( "cryptCreateSession() failed with error code %d, line %d.\n",
1400  status, __LINE__ );
1401  return( FALSE );
1402  }
1403 
1404  /* Open the device/create the keyset to contain the keys. This doesn't
1405  perform a full device.c-style auto-configure but assumes that it's
1406  talking to a device that's already been initialised and is ready to
1407  go */
1408  if( useDevice )
1409  {
1410  status = cryptDeviceOpen( &cryptKeyset, CRYPT_UNUSED,
1412  TEXT( "[Autodetect]" ) );
1413  if( cryptStatusError( status ) )
1414  {
1415  printf( "Crypto device open failed with error code %d, "
1416  "line %d.\n", status, __LINE__ );
1417  return( FALSE );
1418  }
1419  status = cryptSetAttributeString( cryptKeyset,
1421  "test", 4 );
1422  if( cryptStatusError( status ) )
1423  {
1424  printf( "\nDevice login failed with error code %d, line %d.\n",
1425  status, __LINE__ );
1426  return( FALSE );
1427  }
1428  if( cryptDeleteKey( cryptKeyset, CRYPT_KEYID_NAME,
1429  TEXT( "Signature key" ) ) == CRYPT_OK )
1430  puts( "(Deleted a signature key object, presumably a leftover "
1431  "from a previous run)." );
1432  if( cryptDeleteKey( cryptKeyset, CRYPT_KEYID_NAME,
1433  TEXT( "Encryption key" ) ) == CRYPT_OK )
1434  puts( "(Deleted an encryption key object, presumably a leftover "
1435  "from a previous run)." );
1436  }
1437  else
1438  {
1439  status = cryptKeysetOpen( &cryptKeyset, CRYPT_UNUSED,
1440  CRYPT_KEYSET_FILE, isCaUser ? \
1443  if( cryptStatusError( status ) )
1444  {
1445  printf( "User keyset create failed with error code %d, "
1446  "line %d.\n", status, __LINE__ );
1447  return( FALSE );
1448  }
1449  }
1450 
1451  /* Wait for the server to finish initialising */
1452  if( localSession && waitMutex() == CRYPT_ERROR_TIMEOUT )
1453  {
1454  printf( "Timed out waiting for server to initialise, line %d.\n",
1455  __LINE__ );
1456  return( FALSE );
1457  }
1458 
1459  /* Get information needed for enrolment */
1460  status = pkiGetUserInfo( userID, issuePW, NULL, isCaUser ? \
1461  TEXT( "Test CA PKI user" ) : \
1462  TEXT( "Test PKI user" ) );
1463  if( status == CRYPT_ERROR_NOTAVAIL )
1464  {
1465  /* Certificate store operations aren't available, exit but continue
1466  with other tests */
1467  return( TRUE );
1468  }
1469  else
1470  {
1471  if( !status )
1472  return( FALSE );
1473  }
1474 
1475  /* Set up the information we need for the plug-and-play PKI process */
1476  status = cryptSetAttributeString( cryptSession,
1477  CRYPT_SESSINFO_USERNAME, userID,
1478  paramStrlen( userID ) );
1479  if( cryptStatusOK( status ) )
1480  status = cryptSetAttributeString( cryptSession,
1482  issuePW, paramStrlen( issuePW ) );
1483  if( cryptStatusOK( status ) )
1484  status = cryptSetAttributeString( cryptSession,
1486  caInfoTbl[ CA_CRYPTLIB_PNPPKI ].url,
1487  paramStrlen( caInfoTbl[ CA_CRYPTLIB_PNPPKI ].url ) );
1488  if( cryptStatusOK( status ) )
1489  status = cryptSetAttribute( cryptSession,
1491  cryptKeyset );
1492  if( cryptStatusOK( status ) && useDevice )
1493  {
1494  /* Keygen on a device can take an awfully long time for some devices,
1495  so we set an extended timeout to allow for this */
1497  NET_TIMEOUT );
1498  status = cryptSetAttribute( cryptSession,
1500  NET_TIMEOUT );
1501  }
1502  if( useDevice )
1503  cryptDeviceClose( cryptKeyset );
1504  else
1505  cryptKeysetClose( cryptKeyset );
1506  if( cryptStatusError( status ) )
1507  {
1508  printf( "Addition of session information failed with error code %d, "
1509  "line %d.\n", status, __LINE__ );
1510  return( FALSE );
1511  }
1512 
1513  /* Activate the session */
1514  status = cryptSetAttribute( cryptSession, CRYPT_SESSINFO_ACTIVE, TRUE );
1515  if( cryptStatusError( status ) )
1516  {
1517  printExtError( cryptSession, "Attempt to activate plug-and-play PKI "
1518  "client session", status, __LINE__ );
1519  cryptDestroySession( cryptSession );
1520  return( FALSE );
1521  }
1522 
1523  /* Clean up */
1524  cryptDestroySession( cryptSession );
1525 
1526  /* If this is the intermediate CA certificate, change the password to
1527  allow it to be used with the standard PnP PKI test */
1528  if( isCaUser )
1529  {
1531 
1532  /* Get the newly-issued key */
1533  status = cryptKeysetOpen( &cryptKeyset, CRYPT_UNUSED,
1536  if( cryptStatusOK( status ) )
1537  {
1538  status = cryptGetPrivateKey( cryptKeyset, &cryptKey,
1540  TEXT( "Signature key" ), issuePW );
1541  cryptKeysetClose( cryptKeyset );
1542  }
1543  if( cryptStatusError( status ) )
1544  {
1545  printf( "Certified private-key read failed with error code %d, "
1546  "line %d.\n", status, __LINE__ );
1547  return( FALSE );
1548  }
1549 
1550  /* Replace the keyset with one with the key protected with a
1551  different password */
1552  status = cryptKeysetOpen( &cryptKeyset, CRYPT_UNUSED,
1555  if( cryptStatusOK( status ) )
1556  {
1557  status = cryptAddPrivateKey( cryptKeyset, cryptKey,
1559  cryptKeysetClose( cryptKeyset );
1560  }
1561  cryptDestroyContext( cryptKey );
1562  if( cryptStatusError( status ) )
1563  {
1564  printf( "Certified private-key password change failed with error "
1565  "code %d, line %d.\n", status, __LINE__ );
1566  return( FALSE );
1567  }
1568  }
1569 
1570  return( TRUE );
1571  }
1572 
1573 int testSessionPNPPKI( void )
1574  {
1575  return( connectPNPPKI( FALSE, FALSE, FALSE ) );
1576  }
1577 
1578 /* Test the CMP server */
1579 
1580 static int cmpServerSingleIteration( const CRYPT_CONTEXT cryptPrivateKey,
1581  const CRYPT_KEYSET cryptCertStore,
1582  const BOOLEAN useDevice )
1583  {
1584  CRYPT_SESSION cryptSession;
1585  int status;
1586 
1587  /* Create the CMP session and add the CA key and certificate store */
1588  status = cryptCreateSession( &cryptSession, CRYPT_UNUSED,
1590  if( cryptStatusError( status ) )
1591  {
1592  printf( "SVR: cryptCreateSession() failed with error code %d, line "
1593  "%d.\n", status, __LINE__ );
1594  return( FALSE );
1595  }
1596  status = cryptSetAttribute( cryptSession,
1597  CRYPT_SESSINFO_PRIVATEKEY, cryptPrivateKey );
1598  if( cryptStatusOK( status ) )
1599  status = cryptSetAttribute( cryptSession,
1600  CRYPT_SESSINFO_KEYSET, cryptCertStore );
1601  if( cryptStatusOK( status ) && useDevice )
1602  {
1603  /* Keygen on a device can take an awfully long time for some devices,
1604  so we set an extended timeout to allow for this */
1606  NET_TIMEOUT );
1607  status = cryptSetAttribute( cryptSession,
1609  NET_TIMEOUT );
1610  }
1611  if( cryptStatusError( status ) )
1612  return( attrErrorExit( cryptSession, "SVR: cryptSetAttribute()",
1613  status, __LINE__ ) );
1614  if( !setLocalConnect( cryptSession, 80 ) )
1615  return( FALSE );
1616 
1617  /* Activate the session */
1618  status = activatePersistentServerSession( cryptSession, TRUE );
1619  if( cryptStatusError( status ) )
1620  {
1621  status = extErrorExit( cryptSession, "SVR: Attempt to activate CMP "
1622  "server session", status, __LINE__ );
1623  cryptDestroySession( cryptSession );
1624  return( status );
1625  }
1626 
1627  /* We processed the request, clean up */
1628  cryptDestroySession( cryptSession );
1629  return( TRUE );
1630  }
1631 
1632 static int cmpServer( void )
1633  {
1634  CRYPT_SESSION cryptSession;
1635  CRYPT_CONTEXT cryptCAKey;
1636  CRYPT_KEYSET cryptCertStore;
1637  int i, status;
1638 
1639  /* Acquire the init mutex */
1640  acquireMutex();
1641 
1642  puts( "SVR: Testing CMP server session..." );
1643 
1644  /* Perform a test create of a CMP server session to verify that we can
1645  do this test */
1646  status = cryptCreateSession( &cryptSession, CRYPT_UNUSED,
1648  if( status == CRYPT_ERROR_PARAM3 ) /* CMP session access not available */
1649  return( CRYPT_ERROR_NOTAVAIL );
1650  if( cryptStatusError( status ) )
1651  {
1652  printf( "SVR: cryptCreateSession() failed with error code %d, "
1653  "line %d.\n", status, __LINE__ );
1654  return( FALSE );
1655  }
1656  cryptDestroySession( cryptSession );
1657 
1658  /* Set up the server-side objects */
1659  if( !pkiServerInit( &cryptCAKey, &cryptCertStore, CA_PRIVKEY_FILE,
1660  CA_PRIVKEY_LABEL, cmpPkiUserFullDNData,
1661  cmpPkiUserPartialDNData, cmpPkiUserCaData,
1662  "CMP" ) )
1663  return( FALSE );
1664 
1665  /* Tell the client that we're ready to go */
1666  releaseMutex();
1667 
1668  /* Run the server several times to handle the different requests */
1669  for( i = 0; i < NO_CA_REQUESTS; i++ )
1670  {
1671  printf( "SVR: Running server iteration %d.\n", i + 1 );
1672  if( !cmpServerSingleIteration( cryptCAKey, cryptCertStore, FALSE ) )
1673  {
1674 #if defined( SERVER_IS_CRYPTLIB ) && defined( TEST_DUP_IR )
1675  /* If we're running the loopback test and this is the second
1676  iteration, the client is testing the ability to detect a
1677  duplicate ir, so a failure is expected */
1678  if( i == 1 )
1679  {
1680  puts( "SVR: Failure was due to a rejected duplicate request "
1681  "from the client,\n continuing..." );
1682  continue;
1683  }
1684 #endif /* SERVER_IS_CRYPTLIB && TEST_DUP_IR */
1685  break;
1686  }
1687  }
1688  if( i < NO_CA_REQUESTS )
1689  {
1690  if( i == 0 )
1691  return( FALSE );
1692  printf( "SVR: Only %d of %d server requests were processed.\n", i,
1693  NO_CA_REQUESTS );
1694  return( FALSE );
1695  }
1696  puts( "SVR: All server requests were successfully processed." );
1697 
1698  /* Issue a CRL to make sure that the revocation was performed correctly.
1699  We do this now because the certificate management self-test can't
1700  easily perform the check because it requires a CMP-revoked
1701  certificate in order to function */
1702  if( i >= NO_CA_REQUESTS )
1703  {
1704  CRYPT_CERTIFICATE cryptCRL;
1705  int noEntries = 0;
1706 
1707  /* Issue the CRL */
1709  cryptCertStore, cryptCAKey,
1710  CRYPT_UNUSED );
1711  if( cryptStatusError( status ) )
1712  return( extErrorExit( cryptCertStore, "cryptCACertManagement()",
1713  status, __LINE__ ) );
1714 
1715  /* Make sure that the CRL contains at least one entry */
1716  if( cryptStatusOK( cryptSetAttribute( cryptCRL,
1718  CRYPT_CURSOR_FIRST ) ) )
1719  do
1720  noEntries++;
1721  while( cryptSetAttribute( cryptCRL,
1723  CRYPT_CURSOR_NEXT ) == CRYPT_OK );
1724  if( noEntries <= 0 )
1725  {
1726  puts( "CRL created from revoked certificate is empty, should "
1727  "contain at least one\ncertificate entry." );
1728  return( FALSE );
1729  }
1730 
1731  /* Clean up */
1732  cryptDestroyCert( cryptCRL );
1733  }
1734 
1735  /* Clean up */
1736  cryptKeysetClose( cryptCertStore );
1737  cryptDestroyContext( cryptCAKey );
1738  puts( "SVR: CMP session succeeded.\n" );
1739  return( TRUE );
1740  }
1741 
1742 int testSessionCMPServer( void )
1743  {
1744  int status;
1745 
1746  createMutex();
1747  status = cmpServer();
1748  destroyMutex();
1749 
1750  return( status );
1751  }
1752 
1753 static int cmpServerFail( void )
1754  {
1755  CRYPT_CONTEXT cryptCAKey;
1756  CRYPT_KEYSET cryptCertStore;
1757  int i;
1758 
1759  /* Acquire the init mutex */
1760  acquireMutex();
1761 
1762  puts( "SVR: Testing CMP server for rejection of invalid requests..." );
1763 
1764  /* Set up the server-side objects */
1765  if( !pkiServerInit( &cryptCAKey, &cryptCertStore, CA_PRIVKEY_FILE,
1766  CA_PRIVKEY_LABEL, cmpPkiUserFullDNData,
1767  cmpPkiUserPartialDNData, cmpPkiUserCaData,
1768  "CMP" ) )
1769  return( FALSE );
1770 
1771  /* Tell the client that we're ready to go */
1772  releaseMutex();
1773 
1774  /* Run the server several times to handle the different requests, which
1775  should all be rejected */
1776  for( i = 0; i < 3; i++ )
1777  {
1778  printf( "SVR: Running server iteration %d.\n", i + 1 );
1779  if( cmpServerSingleIteration( cryptCAKey, cryptCertStore, FALSE ) )
1780  {
1781  puts( "SVR: CMP request succeeded when it should have "
1782  "failed.\n" );
1783  return( FALSE );
1784  }
1785  }
1786 
1787  /* Clean up */
1788  cryptKeysetClose( cryptCertStore );
1789  cryptDestroyContext( cryptCAKey );
1790 
1791  puts( "SVR: CMP invalid requests successfully rejected.\n" );
1792  return( TRUE );
1793  }
1794 
1795 /* Perform a client/server loopback test */
1796 
1797 #ifdef WINDOWS_THREADS
1798 
1799 static int pnppkiServer( const BOOLEAN pkiBootOnly, const BOOLEAN isCaUser,
1800  const BOOLEAN isIntermediateCA,
1801  const BOOLEAN useDevice )
1802  {
1803  CRYPT_CONTEXT cryptCAKey;
1804  CRYPT_KEYSET cryptCertStore;
1805 
1806  /* Acquire the PNP PKI init mutex */
1807  acquireMutex();
1808 
1809  printf( "SVR: Testing %s server session%s...\n",
1810  pkiBootOnly ? "PKIBoot" : "plug-and-play PKI",
1811  isCaUser ? " for CA certificate" : \
1812  isIntermediateCA ? " using intermediate CA" : "" );
1813 
1814  /* Get the information needed by the server */
1815  if( isIntermediateCA )
1816  {
1817  /* The intermediate CA has a PnP-generated, so the key label is
1818  the predefined PnP signature key one */
1819  if( !pkiServerInit( &cryptCAKey, &cryptCertStore,
1820  PNPCA_PRIVKEY_FILE, TEXT( "Signature key" ),
1821  cmpPkiUserFullDNData, cmpPkiUserPartialDNData,
1822  cmpPkiUserCaData, "CMP" ) )
1823  return( FALSE );
1824  }
1825  else
1826  {
1827  if( !pkiServerInit( &cryptCAKey, &cryptCertStore, CA_PRIVKEY_FILE,
1828  CA_PRIVKEY_LABEL, cmpPkiUserFullDNData,
1829  cmpPkiUserPartialDNData, cmpPkiUserCaData,
1830  "CMP" ) )
1831  return( FALSE );
1832  }
1833 
1834  /* Tell the client that we're ready to go */
1835  releaseMutex();
1836 
1837  /* Run the server once to handle the plug-and-play PKI process */
1838  if( !cmpServerSingleIteration( cryptCAKey, cryptCertStore, useDevice ) )
1839  return( FALSE );
1840 
1841  /* Clean up */
1842  cryptKeysetClose( cryptCertStore );
1843  cryptDestroyContext( cryptCAKey );
1844 
1845  puts( "SVR: Plug-and-play PKI session succeeded.\n" );
1846  return( TRUE );
1847  }
1848 
1849 unsigned __stdcall cmpServerThread( void *dummy )
1850  {
1851  cmpServer();
1852  _endthreadex( 0 );
1853  return( 0 );
1854  }
1855 
1856 int testSessionCMPClientServer( void )
1857  {
1858  HANDLE hThread;
1859  unsigned threadID;
1860  int status;
1861 
1862 #ifndef SERVER_IS_CRYPTLIB
1863  /* Because the code has to handle so many CA-specific peculiarities, we
1864  can only perform this test when the CA being used is the cryptlib
1865  CA */
1866  puts( "Error: The local CMP session test only works with the cryptlib "
1867  "CA." );
1868  return( FALSE );
1869 #endif /* !SERVER_IS_CRYPTLIB */
1870 
1871  /* Start the server */
1872  createMutex();
1873  hThread = ( HANDLE ) _beginthreadex( NULL, 0, cmpServerThread,
1874  NULL, 0, &threadID );
1875  Sleep( 1000 );
1876 
1877  /* Connect to the local server */
1878  status = connectCryptlibCMP( FALSE, TRUE );
1879  waitForThread( hThread );
1880  destroyMutex();
1881  return( status );
1882  }
1883 
1885  {
1886  HANDLE hThread;
1887  unsigned threadID;
1888  int value, status;
1889 
1890 #ifndef SERVER_IS_CRYPTLIB
1891  /* Because the code has to handle so many CA-specific peculiarities, we
1892  can only perform this test when the CA being used is the cryptlib
1893  CA */
1894  puts( "Error: The local CMP session test only works with the cryptlib "
1895  "CA." );
1896  return( FALSE );
1897 #endif /* !SERVER_IS_CRYPTLIB */
1898 
1899  /* Switch the hash algorithm to SHA-2 */
1902  CRYPT_ALGO_SHA2 );
1903 
1904  /* Start the server */
1905  createMutex();
1906  hThread = ( HANDLE ) _beginthreadex( NULL, 0, cmpServerThread,
1907  NULL, 0, &threadID );
1908  Sleep( 1000 );
1909 
1910  /* Connect to the local server */
1911  status = connectCryptlibCMP( FALSE, TRUE );
1912  waitForThread( hThread );
1913  destroyMutex();
1915 
1916  return( status );
1917  }
1918 
1919 unsigned __stdcall cmpPKIBootServerThread( void *dummy )
1920  {
1921  pnppkiServer( TRUE, FALSE, FALSE, FALSE );
1922  _endthreadex( 0 );
1923  return( 0 );
1924  }
1925 
1927  {
1928  HANDLE hThread;
1929  unsigned threadID;
1930  int status;
1931 
1932 #ifndef SERVER_IS_CRYPTLIB
1933  /* Because the code has to handle so many CA-specific peculiarities, we
1934  can only perform this test when the CA being used is the cryptlib
1935  CA */
1936  puts( "Error: The local CMP session test only works with the cryptlib "
1937  "CA." );
1938  return( FALSE );
1939 #endif /* !SERVER_IS_CRYPTLIB */
1940 
1941  /* Start the server */
1942  createMutex();
1943  hThread = ( HANDLE ) _beginthreadex( NULL, 0, cmpPKIBootServerThread,
1944  NULL, 0, &threadID );
1945  Sleep( 1000 );
1946 
1947  /* Connect to the local server with PKIBoot enabled */
1948  status = connectCryptlibCMP( TRUE, TRUE );
1949  waitForThread( hThread );
1950  destroyMutex();
1951  return( status );
1952  }
1953 
1954 unsigned __stdcall cmpPnPPKIServerThread( void *dummy )
1955  {
1956  /* Call with the third parameter set to TRUE to use a chain of CA certs
1957  (i.e. an intermediate CA between the root and end user) rather than
1958  a single CA certificate directly issuing the certificate to the end
1959  user */
1960  pnppkiServer( FALSE, FALSE, FALSE, FALSE );
1961  _endthreadex( 0 );
1962  return( 0 );
1963  }
1964 
1966  {
1967  HANDLE hThread;
1968  unsigned threadID;
1969  int status;
1970 
1971  /* Start the server */
1972  createMutex();
1973  hThread = ( HANDLE ) _beginthreadex( NULL, 0, cmpPnPPKIServerThread,
1974  NULL, 0, &threadID );
1975  Sleep( 1000 );
1976 
1977  /* Connect to the local server with PKIBoot enabled */
1978  status = connectPNPPKI( FALSE, FALSE, TRUE );
1979  waitForThread( hThread );
1980  destroyMutex();
1981  return( status );
1982  }
1983 
1984 unsigned __stdcall cmpPnPPKIDeviceServerThread( void *dummy )
1985  {
1986  /* Call with the third parameter set to TRUE to use a chain of CA certs
1987  (i.e. an intermediate CA between the root and end user) rather than
1988  a single CA certificate directly issuing the certificate to the end
1989  user */
1990  pnppkiServer( FALSE, FALSE, FALSE, TRUE );
1991  _endthreadex( 0 );
1992  return( 0 );
1993  }
1994 
1996  {
1997  HANDLE hThread;
1998  unsigned threadID;
1999  int status;
2000 
2001  /* Start the server */
2002  createMutex();
2003  hThread = ( HANDLE ) _beginthreadex( NULL, 0, cmpPnPPKIDeviceServerThread,
2004  NULL, 0, &threadID );
2005  Sleep( 1000 );
2006 
2007  /* Connect to the local server with PKIBoot enabled */
2008  status = connectPNPPKI( FALSE, TRUE, TRUE );
2009  waitForThread( hThread );
2010  destroyMutex();
2011  return( status );
2012  }
2013 
2014 unsigned __stdcall cmpPnPPKICaServerThread( void *dummy )
2015  {
2016  pnppkiServer( FALSE, TRUE, FALSE, FALSE );
2017  _endthreadex( 0 );
2018  return( 0 );
2019  }
2020 
2022  {
2023  HANDLE hThread;
2024  unsigned threadID;
2025  int status;
2026 
2027  /* Start the server */
2028  createMutex();
2029  hThread = ( HANDLE ) _beginthreadex( NULL, 0, cmpPnPPKICaServerThread,
2030  NULL, 0, &threadID );
2031  Sleep( 1000 );
2032 
2033  /* Connect to the local server with PKIBoot enabled */
2034  status = connectPNPPKI( TRUE, FALSE, TRUE );
2035  waitForThread( hThread );
2036  destroyMutex();
2037  return( status );
2038  }
2039 
2040 unsigned __stdcall cmpPnPPKIIntermedCaServerThread( void *dummy )
2041  {
2042  pnppkiServer( FALSE, FALSE, TRUE, FALSE );
2043  _endthreadex( 0 );
2044  return( 0 );
2045  }
2046 
2048  {
2049  HANDLE hThread;
2050  unsigned threadID;
2051  int status;
2052 
2053  /* Start the server */
2054  createMutex();
2055  hThread = ( HANDLE ) _beginthreadex( NULL, 0, cmpPnPPKIIntermedCaServerThread,
2056  NULL, 0, &threadID );
2057  Sleep( 1000 );
2058 
2059  /* Connect to the local server with PKIBoot enabled */
2060  status = connectPNPPKI( FALSE, FALSE, TRUE );
2061  waitForThread( hThread );
2062  destroyMutex();
2063  return( status );
2064  }
2065 
2066 unsigned __stdcall cmpFailServerThread( void *dummy )
2067  {
2068  cmpServerFail();
2069  _endthreadex( 0 );
2070  return( 0 );
2071  }
2072 
2074  {
2075  HANDLE hThread;
2076  unsigned threadID;
2077  int status;
2078 
2079  /* Start the server */
2080  createMutex();
2081  hThread = ( HANDLE ) _beginthreadex( NULL, 0, cmpFailServerThread,
2082  NULL, 0, &threadID );
2083  Sleep( 1000 );
2084 
2085  /* Connect to the local server with several requests that should fail */
2086  status = connectCMPFail( 0 );
2087  if( status )
2088  status = connectCMPFail( 1 );
2089  if( status )
2090  status = connectCMPFail( 2 );
2091  waitForThread( hThread );
2092  destroyMutex();
2093  return( status );
2094  }
2095 #endif /* WINDOWS_THREADS */
2096 
2097 #endif /* TEST_SESSION || TEST_SESSION_LOOPBACK */