cryptlib  3.4.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros
s_scep.c
Go to the documentation of this file.
1 /****************************************************************************
2 * *
3 * cryptlib SCEP 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 defined( TEST_SESSION ) || defined( TEST_SESSION_LOOPBACK )
20 
21 /****************************************************************************
22 * *
23 * SCEP Test Data *
24 * *
25 ****************************************************************************/
26 
27 /* There are various SCEP test servers available, the following mappings
28  can be used to test different ones. Implementation peculiarities:
29 
30  #1 - cryptlib: None.
31 
32  #2 - SSH (www.ssh.com/support/testzone/pki.html): Invalid CA
33  certificates.
34 
35  #3 - OpenSCEP (openscep.othello.ch): Seems to be permanently unavailable.
36 
37  #4 - Entrust (freecerts.entrust.com/vpncerts/cep.htm): Only seems to be
38  set up to handle Cisco gear.
39 
40  #5 - EJBCA:
41 
42  #6 - Insta-Certifier: Information at
43  http://www.certificate.fi/resources/demos/demo.htm.
44 
45  #7 - Microsoft NDES: Invalid CA certificates, set compliance level to
46  CRYPT_COMPLIANCELEVEL_OBLIVIOUS to handle this. GetCACaps
47  (via http://qa4-mdm3.qa4.imdmdemo.com/certsrv/mscep/?operation=GetCACaps)
48  is implemented but broken, returns a zero-length response */
49 
50 #define SCEP_NO 1
51 
52 typedef struct {
53  const char FAR_BSS *name;
54  const C_CHR FAR_BSS *url, FAR_BSS *user, FAR_BSS *password, FAR_BSS *caCertUrl;
55  } SCEP_INFO;
56 
57 static const SCEP_INFO FAR_BSS scepInfo[] = {
58  { NULL }, /* Dummy so index == SCEP_NO */
59  { /*1*/ "cryptlib", TEXT( "http://localhost/pkiclient.exe" ), NULL, NULL, NULL },
60  /* The CA certificate URL may be overridden by passing a
61  CA-cert-read flag to the SCEP client function, it's tested
62  both with an explicitly-added certificate via a file and
63  an implicitly-read certificate via GetCACert */
64  { /*2*/ "SSH", TEXT( "http://pki.ssh.com:8080/scep/pkiclient.exe" ),
65  TEXT( "ssh" ), TEXT( "ssh" ),
66  TEXT( "http://pki.ssh.com:8080/scep/pkiclient.exe?operation=GetCACert&message=test-ca1.ssh.com" ) },
67  { /*3*/ "OpenSCEP", TEXT( "http://openscep.othello.ch/pkiclient.exe" ),
68  TEXT( "????" ), TEXT( "????" ), NULL },
69  { /*4*/ "Entrust", TEXT( "http://vpncerts.entrust.com/pkiclient.exe" ),
70  TEXT( "????" ), TEXT( "????" ), NULL },
71  { /*5*/ "EJBCA", TEXT( "http://q-rl-xp:8080/ejbca/publicweb/apply/scep/pkiclient.exe" ),
72  TEXT("test2"), TEXT("test2"),
73  TEXT( "http://q-rl-xp:8080/ejbca/publicweb/webdist/certdist?cmd=nscacert&issuer=O=Test&+level=1" ) },
74  { /*6*/ "SSH", TEXT( "http://pki.certificate.fi:8082/scep/" ),
75  NULL, TEXT( "scep" ), NULL },
76  { /*7*/ "Microsoft NDES", TEXT( "http://qa4-mdm3.qa4.imdmdemo.com" ),
77  TEXT( "cryptlibtest" ), TEXT( "password!1" ),
78  TEXT( "http://qa4-mdm3.qa4.imdmdemo.com/certsrv/mscep/?operation=GetCACert&message=qa" ) }
79  };
80 
81 /* Certificate request data for the certificate from the SCEP server. Note
82  that we have to set the CN to the PKI user CN, for CMP ir's we just omit
83  the DN entirely and have the server provide it for us but since SCEP uses
84  PKCS #10 requests we need to provide a DN, and since we provide it it has
85  to match the PKI user DN */
86 
87 static const CERT_DATA FAR_BSS scepRequestData[] = {
88  /* Identification information */
89  { CRYPT_CERTINFO_COUNTRYNAME, IS_STRING, 0, TEXT( "NZ" ) },
90  { CRYPT_CERTINFO_ORGANIZATIONNAME, IS_STRING, 0, TEXT( "Dave's Wetaburgers" ) },
91  { CRYPT_CERTINFO_ORGANIZATIONALUNITNAME, IS_STRING, 0, TEXT( "Procurement" ) },
92  { CRYPT_CERTINFO_COMMONNAME, IS_STRING, 0, TEXT( "Test SCEP PKI user" ) },
93 
94  /* Subject altName */
96  { CRYPT_CERTINFO_UNIFORMRESOURCEIDENTIFIER, IS_STRING, 0, TEXT( "http://www.wetas-r-us.com" ) },
97 
99  };
100 
101 /* PKI user data to authorise the issuing of the various certs */
102 
103 static const CERT_DATA FAR_BSS scepPkiUserData[] = {
104  /* Identification information */
105  { CRYPT_CERTINFO_COUNTRYNAME, IS_STRING, 0, TEXT( "NZ" ) },
106  { CRYPT_CERTINFO_ORGANIZATIONNAME, IS_STRING, 0, TEXT( "Dave's Wetaburgers" ) },
107  { CRYPT_CERTINFO_ORGANIZATIONALUNITNAME, IS_STRING, 0, TEXT( "Procurement" ) },
108  { CRYPT_CERTINFO_COMMONNAME, IS_STRING, 0, TEXT( "Test SCEP PKI user" ) },
109 
111  };
112 
113 /****************************************************************************
114 * *
115 * Utility Functions *
116 * *
117 ****************************************************************************/
118 
119 /* Add a PKI user to the certificate store */
120 
121 static int addPKIUser( const CRYPT_KEYSET cryptCertStore,
122  const CERT_DATA *pkiUserData,
123  const BOOLEAN isSCEP,
124  const BOOLEAN testErrorChecking )
125  {
126  CRYPT_CERTIFICATE cryptPKIUser;
127  CRYPT_SESSION cryptSession;
128  C_CHR userID[ CRYPT_MAX_TEXTSIZE + 1 ], issuePW[ CRYPT_MAX_TEXTSIZE + 1 ];
129  int length, status;
130 
131  puts( "-- Adding new PKI user information --" );
132 
133  /* Create the PKI user object and add the user's identification
134  information */
135  status = cryptCreateCert( &cryptPKIUser, CRYPT_UNUSED,
137  if( cryptStatusError( status ) )
138  {
139  printf( "cryptCreateCert() failed with error code %d, line %d.\n",
140  status, __LINE__ );
141  return( FALSE );
142  }
143  if( !addCertFields( cryptPKIUser, pkiUserData, __LINE__ ) )
144  return( FALSE );
145 
146  /* Add the user info to the certificate store */
147  status = cryptCAAddItem( cryptCertStore, cryptPKIUser );
148  if( status == CRYPT_ERROR_DUPLICATE )
149  {
150  C_CHR userIdentifier[ CRYPT_MAX_TEXTSIZE + 1 ];
151 
152  /* Get the name of the duplicate user. Since this may be just a
153  template we fall back to higher-level DN components if there's
154  no CN present */
155  status = cryptGetAttributeString( cryptPKIUser,
157  userIdentifier, &length );
158  if( status == CRYPT_ERROR_NOTFOUND )
159  status = cryptGetAttributeString( cryptPKIUser,
161  userIdentifier, &length );
162  if( status == CRYPT_ERROR_NOTFOUND )
163  status = cryptGetAttributeString( cryptPKIUser,
165  userIdentifier, &length );
166  if( cryptStatusError( status ) )
167  return( attrErrorExit( cryptPKIUser, "cryptGetAttribute()",
168  status, __LINE__ ) );
169 #ifdef UNICODE_STRINGS
170  length /= sizeof( wchar_t );
171 #endif /* UNICODE_STRINGS */
172  userIdentifier[ length ] = TEXT( '\0' );
173 
174  /* The PKI user info was already present, for SCEP this isn't a
175  problem since we can just re-use the existing info, but for CMP
176  we can only authorise a single certificate issue per user so we
177  have to delete the existing user info and try again */
178  if( isSCEP )
179  {
180  /* The PKI user info is already present from a previous run, get
181  the existing info */
182  puts( "PKI user information is already present from a previous "
183  "run, reusing existing\n PKI user data..." );
184  cryptDestroyCert( cryptPKIUser );
185  status = cryptCAGetItem( cryptCertStore, &cryptPKIUser,
187  userIdentifier );
188  }
189  else
190  {
191  puts( "PKI user information is already present from a previous "
192  "run, deleting existing\n PKI user data..." );
193  status = cryptCADeleteItem( cryptCertStore, CRYPT_CERTTYPE_PKIUSER,
194  CRYPT_KEYID_NAME, userIdentifier );
195  if( cryptStatusError( status ) )
196  return( extErrorExit( cryptCertStore, "cryptCADeleteItem()",
197  status, __LINE__ ) );
198  status = cryptCAAddItem( cryptCertStore, cryptPKIUser );
199  }
200  }
201  if( cryptStatusError( status ) )
202  return( extErrorExit( cryptCertStore, "cryptCAAdd/GetItem()", status,
203  __LINE__ ) );
204 
205  /* Display the information for the new user */
206  if( !printCertInfo( cryptPKIUser ) )
207  return( FALSE );
208  status = cryptGetAttributeString( cryptPKIUser,
210  userID, &length );
211  if( cryptStatusOK( status ) )
212  {
213 #ifdef UNICODE_STRINGS
214  length /= sizeof( wchar_t );
215 #endif /* UNICODE_STRINGS */
216  userID[ length ] = '\0';
217  status = cryptGetAttributeString( cryptPKIUser,
219  issuePW, &length );
220  }
221  if( cryptStatusOK( status ) )
222  {
223 #ifdef UNICODE_STRINGS
224  length /= sizeof( wchar_t );
225 #endif /* UNICODE_STRINGS */
226  issuePW[ length ] = '\0';
227  }
228  else
229  {
230  return( attrErrorExit( cryptPKIUser, "cryptGetAttribute()", status,
231  __LINE__ ) );
232  }
233  puts( "-- New PKI user information ends --\n" );
234 
235  /* If we're not testing the error-checking capability of the user
236  identifiers, we're done */
237  if( !testErrorChecking )
238  {
239  cryptDestroyCert( cryptPKIUser );
240  return( TRUE );
241  }
242 
243  /* Make sure that the error-checking in the user information works via a
244  dummy CMP client session. We have to check both passwords to reduce
245  false positives since it's just a simple integrity check meant to
246  catch typing errors rather than a cryptographically strong check */
247  status = cryptCreateSession( &cryptSession, CRYPT_UNUSED,
249  if( cryptStatusError( status ) )
250  return( FALSE );
251  if( userID[ 2 ] >= TEXT( 'A' ) && userID[ 2 ] < TEXT( 'Z' ) )
252  userID[ 2 ]++;
253  else
254  userID[ 2 ] = TEXT( 'A' );
255  if( issuePW[ 8 ] >= TEXT( 'A' ) && issuePW[ 8 ] < TEXT( 'Z' ) )
256  issuePW[ 8 ]++;
257  else
258  issuePW[ 8 ] = TEXT( 'A' );
259  status = cryptSetAttributeString( cryptSession, CRYPT_SESSINFO_USERNAME,
260  userID, paramStrlen( userID ) );
261  if( cryptStatusOK( status ) )
262  status = cryptSetAttributeString( cryptSession, CRYPT_SESSINFO_PASSWORD,
263  issuePW, paramStrlen( issuePW ) );
264  if( cryptStatusOK( status ) )
265  {
266  puts( "Integrity check of user ID and password failed to catch "
267  "errors in the data.\n(This check isn't foolproof and is "
268  "intended only to catch typing errors when\nentering the "
269  "data. Try running the test again to see if the problem "
270  "still\noccurs)." );
271  return( FALSE );
272  }
273  cryptDestroySession( cryptSession );
274 
275  /* Clean up */
276  cryptDestroyCert( cryptPKIUser );
277  return( TRUE );
278  }
279 
280 /* Get information on a PKI user */
281 
282 int pkiGetUserInfo( C_STR userID, C_STR issuePW, C_STR revPW,
283  const C_STR userName )
284  {
285  CRYPT_KEYSET cryptCertStore;
286  CRYPT_CERTIFICATE cryptPKIUser;
287  int length, status;
288 
289  /* cryptlib implements per-user (rather than shared interop) IDs and
290  passwords so we need to read the user ID and password information
291  before we can perform any operations. First we get the PkiUser
292  object */
293  status = cryptKeysetOpen( &cryptCertStore, CRYPT_UNUSED,
296  if( status == CRYPT_ERROR_PARAM3 )
297  {
298  /* This type of keyset access isn't available, return a special error
299  code to indicate that the test wasn't performed, but that this
300  isn't a reason to abort processing */
301  puts( "No certificate store available, aborting CMP test.\n" );
302  return( CRYPT_ERROR_NOTAVAIL );
303  }
304  if( cryptStatusError( status ) )
305  {
306  printf( "cryptKeysetOpen() failed with error code %d, line %d.\n",
307  status, __LINE__ );
308  return( FALSE );
309  }
310  status = cryptCAGetItem( cryptCertStore, &cryptPKIUser,
312  userName );
313  cryptKeysetClose( cryptCertStore );
314  if( cryptStatusError( status ) )
315  {
316  /* Only report error info if it's not a basic presence check */
317  if( userID != NULL )
318  extErrorExit( cryptCertStore, "cryptCAGetItem()", status, __LINE__ );
319  return( FALSE );
320  }
321 
322  /* If it's a presence check only, we're done */
323  if( userID == NULL )
324  {
325  cryptDestroyCert( cryptPKIUser );
326  return( TRUE );
327  }
328 
329  /* Then we extract the information from the PkiUser object */
330  status = cryptGetAttributeString( cryptPKIUser,
332  userID, &length );
333  if( cryptStatusOK( status ) )
334  {
335  userID[ length ] = '\0';
336  status = cryptGetAttributeString( cryptPKIUser,
338  issuePW, &length );
339  }
340  if( cryptStatusOK( status ) )
341  issuePW[ length ] = '\0';
342  if( cryptStatusOK( status ) && revPW != NULL )
343  {
344  status = cryptGetAttributeString( cryptPKIUser,
346  revPW, &length );
347  if( cryptStatusOK( status ) )
348  revPW[ length ] = '\0';
349  }
350  cryptDestroyCert( cryptPKIUser );
351  if( cryptStatusError( status ) )
352  {
353  attrErrorExit( cryptPKIUser, "cryptGetAttribute()", status,
354  __LINE__ );
355  return( FALSE );
356  }
357 
358  /* We've got what we need, tell the user what we're doing */
359  printf( "Using user name %s, password %s.\n", userID, issuePW );
360  return( TRUE );
361  }
362 
363 /* Set up objects and information needed by a server-side PKI session */
364 
365 int pkiServerInit( CRYPT_CONTEXT *cryptPrivateKey,
366  CRYPT_KEYSET *cryptCertStore, const C_STR keyFileName,
367  const C_STR keyLabel, const CERT_DATA *pkiUserData,
368  const CERT_DATA *pkiUserAltData,
369  const CERT_DATA *pkiUserCAData, const char *protocolName )
370  {
371  const BOOLEAN isSCEP = !strcmp( protocolName, "SCEP" ) ? TRUE : FALSE;
372  int status;
373 
374  /* Get the certificate store to use with the session. Before we use the
375  store we perform a cleanup action to remove any leftover requests from
376  previous runs */
377  status = cryptKeysetOpen( cryptCertStore, CRYPT_UNUSED,
380  if( status == CRYPT_ERROR_PARAM3 )
381  {
382  /* This type of keyset access isn't available, return a special error
383  code to indicate that the test wasn't performed, but that this
384  isn't a reason to abort processing */
385  printf( "SVR: No certificate store available, aborting %s server "
386  "test.\n\n", protocolName );
387  return( CRYPT_ERROR_NOTAVAIL );
388  }
389  if( status == CRYPT_ERROR_DUPLICATE )
390  status = cryptKeysetOpen( cryptCertStore, CRYPT_UNUSED,
393  if( cryptStatusError( status ) )
394  {
395  printf( "SVR: cryptKeysetOpen() failed with error code %d, line "
396  "%d.\n", status, __LINE__ );
397  return( FALSE );
398  }
400  *cryptCertStore, CRYPT_UNUSED,
401  CRYPT_UNUSED );
402  if( cryptStatusError( status ) )
403  {
404  printf( "SVR: CA certificate store cleanup failed with error code %d, "
405  "line %d.\n", status, __LINE__ );
406  return( FALSE );
407  }
408 
409  /* Create the EE and CA PKI users */
410  puts( "Creating PKI user..." );
411  if( !addPKIUser( *cryptCertStore, pkiUserData, isSCEP, !isSCEP ) )
412  return( FALSE );
413  if( pkiUserAltData != NULL && \
414  !addPKIUser( *cryptCertStore, pkiUserAltData, isSCEP, FALSE ) )
415  return( FALSE );
416  if( pkiUserCAData != NULL && \
417  !addPKIUser( *cryptCertStore, pkiUserCAData, isSCEP, FALSE ) )
418  return( FALSE );
419 
420  /* Get the CA's private key */
421  status = getPrivateKey( cryptPrivateKey, keyFileName,
422  keyLabel, TEST_PRIVKEY_PASSWORD );
423  if( cryptStatusError( status ) )
424  {
425  printf( "SVR: CA private key read failed with error code %d, "
426  "line %d.\n", status, __LINE__ );
427  return( FALSE );
428  }
429 
430  return( TRUE );
431  }
432 
433 /****************************************************************************
434 * *
435 * SCEP Routines Test *
436 * *
437 ****************************************************************************/
438 
439 /* Get an SCEP CA certificate */
440 
441 static int getScepCACert( const C_STR caCertUrl,
442  CRYPT_CERTIFICATE *cryptCACert )
443  {
444  CRYPT_KEYSET cryptKeyset;
445  int status;
446 
447  status = cryptKeysetOpen( &cryptKeyset, CRYPT_UNUSED, CRYPT_KEYSET_HTTP,
448  caCertUrl, CRYPT_KEYOPT_READONLY );
449  if( cryptStatusOK( status ) )
450  {
451  status = cryptGetPublicKey( cryptKeyset, cryptCACert, CRYPT_KEYID_NAME,
452  TEXT( "[None]" ) );
453  cryptKeysetClose( cryptKeyset );
454  }
455  if( cryptStatusError( status ) )
456  return( extErrorExit( cryptKeyset, "cryptGetPublicKey()",
457  status, __LINE__ ) );
458 
459  return( TRUE );
460  }
461 
462 /* Perform an SCEP test */
463 
464 static int connectSCEP( const BOOLEAN localSession,
465  const BOOLEAN userSuppliesCACert )
466  {
467  CRYPT_SESSION cryptSession;
468  CRYPT_CERTIFICATE cryptRequest = DUMMY_INIT, cryptResponse, cryptCACert;
470 #if ( SCEP_NO == 1 )
471  C_CHR userID[ 64 ], password[ 64 ];
472  const C_STR userPtr;
473  const C_STR passwordPtr;
474 #else
475  const C_STR userPtr = scepInfo[ SCEP_NO ].user;
476  const C_STR passwordPtr = scepInfo[ SCEP_NO ].password;
477 #endif /* cryptlib SCEP server */
478 #if ( SCEP_NO == 7 )
479  int complianceValue;
480 #endif /* MS NDES SCEP server */
481  int status;
482 
483  printf( "Testing %s SCEP session%s...\n", scepInfo[ SCEP_NO ].name,
484  userSuppliesCACert ? "" : " with CA certificate read" );
485 
486  /* Wait for the server to finish initialising */
487  if( localSession && waitMutex() == CRYPT_ERROR_TIMEOUT )
488  {
489  printf( "Timed out waiting for server to initialise, line %d.\n",
490  __LINE__ );
491  return( FALSE );
492  }
493 
494 #if ( SCEP_NO == 1 )
495  /* If we're doing a loopback test, make sure that the required user info
496  is present. If it isn't, the CA auditing will detect a request from
497  a nonexistant user and refuse to issue a certificate */
498  if( !pkiGetUserInfo( NULL, NULL, NULL, TEXT( "Test SCEP PKI user" ) ) )
499  {
500  puts( "CA certificate store doesn't contain the PKI user "
501  "information needed to\nauthenticate certificate issue "
502  "operations, can't perform SCEP test.\n" );
503  return( CRYPT_ERROR_NOTAVAIL );
504  }
505 #endif /* cryptlib SCEP server */
506 
507 #if ( SCEP_NO == 7 )
508  /* The MS SCEP server certificate is broken so we have to turn down the
509  compliance level to allow it to be used */
511  &complianceValue );
514 #endif /* MS NDES SCEP server */
515 
516  /* Get the issuing CA's certificate if required */
517  if( userSuppliesCACert )
518  {
519  if( scepInfo[ SCEP_NO ].caCertUrl != NULL )
520  {
521  if( !getScepCACert( scepInfo[ SCEP_NO ].caCertUrl,
522  &cryptCACert ) )
523  return( FALSE );
524  }
525  else
526  {
527  status = importCertFromTemplate( &cryptCACert,
528  SCEP_CA_FILE_TEMPLATE, SCEP_NO );
529  if( cryptStatusError( status ) )
530  {
531  printf( "Couldn't get SCEP CA certificate, status = %d, "
532  "line %d.\n", status, __LINE__ );
533  return( FALSE );
534  }
535  }
536  }
537 
538  /* cryptlib implements per-user (rather than shared interop) IDs and
539  passwords so we need to read the user ID and password information
540  before we can perform any operations */
541 #if ( SCEP_NO == 1 )
542  status = pkiGetUserInfo( userID, password, NULL,
543  TEXT( "Test SCEP PKI user" ) );
544  if( !status || status == CRYPT_ERROR_NOTAVAIL )
545  {
546  if( userSuppliesCACert )
547  cryptDestroyCert( cryptCACert );
548 
549  /* If certificate store operations aren't available, exit but
550  continue with other tests, otherwise abort the tests */
551  return( ( status == CRYPT_ERROR_NOTAVAIL ) ? TRUE : FALSE );
552  }
553  userPtr = userID;
554  passwordPtr = password;
555 #endif /* cryptlib SCEP server */
556 
557  /* Create the SCEP session */
558  status = cryptCreateSession( &cryptSession, CRYPT_UNUSED,
560  if( status == CRYPT_ERROR_PARAM3 ) /* SCEP session access not available */
561  return( CRYPT_ERROR_NOTAVAIL );
562  if( cryptStatusError( status ) )
563  {
564  printf( "cryptCreateSession() failed with error code %d, line %d.\n",
565  status, __LINE__ );
566  return( FALSE );
567  }
568 
569  /* Make sure that the SCEP client's checking for invalid transactionIDs
570  works (this is an obscure problem caused by the SCEP protocol, see
571  the SCEP client code comments for more information) */
572  status = cryptSetAttributeString( cryptSession,
574  TEXT( "abc@def" ),
575  paramStrlen( TEXT( "abc@def" ) ) );
576  if( cryptStatusOK( status ) )
577  {
578  printf( "Addition of invalid SCEP user information wasn't detected, "
579  "line %d.\n", __LINE__ );
580  return( FALSE );
581  }
582 
583  /* Set up the user and server information */
584  status = cryptSetAttributeString( cryptSession,
586  userPtr, paramStrlen( userPtr ) );
587  if( cryptStatusOK( status ) )
588  status = cryptSetAttributeString( cryptSession,
590  passwordPtr, paramStrlen( passwordPtr ) );
591  if( cryptStatusOK( status ) )
592  status = cryptSetAttributeString( cryptSession,
594  scepInfo[ SCEP_NO ].url,
595  paramStrlen( scepInfo[ SCEP_NO ].url ) );
596  if( userSuppliesCACert )
597  {
598  if( cryptStatusOK( status ) )
599  status = cryptSetAttribute( cryptSession,
601  cryptCACert );
602  cryptDestroyCert( cryptCACert );
603  }
604  if( cryptStatusError( status ) )
605  {
606  printf( "Addition of SCEP user/server information failed with error "
607  "code %d, line %d.\n", status, __LINE__ );
608  return( FALSE );
609  }
610 
611  /* Create the (unsigned) PKCS #10 request */
612 #if ( SCEP_NO == 1 )
613  status = cryptCreateContext( &cryptContext, CRYPT_UNUSED,
614  CRYPT_ALGO_RSA );
615  if( cryptStatusError( status ) )
616  return( FALSE );
620  status = cryptGenerateKey( cryptContext );
621  if( cryptStatusOK( status ) )
622 #else
623  loadRSAContextsEx( CRYPT_UNUSED, NULL, &cryptContext, NULL,
625 #endif /* cryptlib SCEP server */
626  status = cryptCreateCert( &cryptRequest, CRYPT_UNUSED,
628  if( cryptStatusOK( status ) )
629  status = cryptSetAttribute( cryptRequest,
630  CRYPT_CERTINFO_SUBJECTPUBLICKEYINFO, cryptContext );
631  if( cryptStatusOK( status ) && \
632  !addCertFields( cryptRequest, scepRequestData, __LINE__ ) )
633  status = CRYPT_ERROR_FAILED;
634 #if 0
635  if( cryptStatusOK( status ) )
636  status = cryptSignCert( cryptRequest, cryptContext );
637 #endif
638  if( cryptStatusError( status ) )
639  {
640  printf( "Creation of PKCS #10 request failed with error code %d, "
641  "line %d.\n", status, __LINE__ );
642  return( FALSE );
643  }
644 
645  /* Set up the private key and request, and activate the session */
646  status = cryptSetAttribute( cryptSession, CRYPT_SESSINFO_PRIVATEKEY,
647  cryptContext );
648  cryptDestroyContext( cryptContext );
649  if( cryptStatusOK( status ) )
650  status = cryptSetAttribute( cryptSession, CRYPT_SESSINFO_REQUEST,
651  cryptRequest );
652  cryptDestroyCert( cryptRequest );
653  if( cryptStatusError( status ) )
654  {
655  printf( "cryptSetAttribute() failed with error code %d, line %d.\n",
656  status, __LINE__ );
657  return( FALSE );
658  }
659  status = cryptSetAttribute( cryptSession, CRYPT_SESSINFO_ACTIVE, TRUE );
660  if( cryptStatusError( status ) )
661  {
662  printExtError( cryptSession, "Attempt to activate SCEP client "
663  "session", status, __LINE__ );
664  cryptDestroySession( cryptSession );
665  if( status == CRYPT_ERROR_OPEN || status == CRYPT_ERROR_READ )
666  {
667  /* These servers are constantly appearing and disappearing so if
668  we get a straight connect error we don't treat it as a serious
669  failure */
670  puts( " (Server could be down, faking it and continuing...)\n" );
671  return( CRYPT_ERROR_FAILED );
672  }
673  return( FALSE );
674  }
675 
676 #if ( SCEP_NO == 7 )
677  /* Restore normal certificate checking */
679  complianceValue );
680 #endif /* MS NDES SCEP server */
681 
682  /* Print the session security information */
683  printFingerprint( cryptSession, FALSE );
684 
685  /* Obtain the response information */
686  status = cryptGetAttribute( cryptSession, CRYPT_SESSINFO_RESPONSE,
687  &cryptResponse );
688  if( cryptStatusOK( status ) && !userSuppliesCACert )
689  status = cryptGetAttribute( cryptSession, CRYPT_SESSINFO_RESPONSE,
690  &cryptCACert );
691  cryptDestroySession( cryptSession );
692  if( cryptStatusError( status ) )
693  {
694  printf( "cryptGetAttribute() failed with error code %d, line %d.\n",
695  status, __LINE__ );
696  return( FALSE );
697  }
698 #if ( SCEP_NO != 1 )
699  puts( "Returned certificate details are:" );
700  printCertInfo( cryptResponse );
701  if( !userSuppliesCACert )
702  {
703  puts( "Returned CA certificate details are:" );
704  printCertInfo( cryptCACert );
705  }
706 #endif /* Keep the cryptlib results on one screen */
707 
708  /* Clean up */
709  cryptDestroyCert( cryptResponse );
710  if( !userSuppliesCACert )
711  cryptDestroyCert( cryptCACert );
712  puts( "SCEP client session succeeded.\n" );
713  return( TRUE );
714  }
715 
716 int testSessionSCEP( void )
717  {
718  return( connectSCEP( FALSE, TRUE ) );
719  }
720 
721 int testSessionSCEPCACert( void )
722  {
723  return( connectSCEP( FALSE, FALSE ) );
724  }
725 
726 static int scepServer( void )
727  {
728  CRYPT_SESSION cryptSession;
729  CRYPT_CONTEXT cryptCAKey;
730  CRYPT_KEYSET cryptCertStore;
731  int status;
732 
733  /* Acquire the init mutex */
734  acquireMutex();
735 
736  puts( "SVR: Testing SCEP server session ..." );
737 
738  /* Perform a test create of a SCEP server session to verify that we can
739  do this test */
740  status = cryptCreateSession( &cryptSession, CRYPT_UNUSED,
742  if( status == CRYPT_ERROR_PARAM3 ) /* SCEP session access not available */
743  return( CRYPT_ERROR_NOTAVAIL );
744  if( cryptStatusError( status ) )
745  {
746  printf( "SVR: cryptCreateSession() failed with error code %d, "
747  "line %d.\n", status, __LINE__ );
748  return( FALSE );
749  }
750  cryptDestroySession( cryptSession );
751 
752  /* Set up the server-side objects */
753  if( !pkiServerInit( &cryptCAKey, &cryptCertStore, SCEPCA_PRIVKEY_FILE,
754  USER_PRIVKEY_LABEL, scepPkiUserData, NULL, NULL,
755  "SCEP" ) )
756  return( FALSE );
757 
758  /* Create the SCEP session and add the CA key and certificate store */
759  status = cryptCreateSession( &cryptSession, CRYPT_UNUSED,
761  if( cryptStatusError( status ) )
762  {
763  printf( "SVR: cryptCreateSession() failed with error code %d, line "
764  "%d.\n", status, __LINE__ );
765  return( FALSE );
766  }
767  status = cryptSetAttribute( cryptSession,
768  CRYPT_SESSINFO_PRIVATEKEY, cryptCAKey );
769  if( cryptStatusOK( status ) )
770  status = cryptSetAttribute( cryptSession,
771  CRYPT_SESSINFO_KEYSET, cryptCertStore );
772  if( cryptStatusError( status ) )
773  return( attrErrorExit( cryptSession, "SVR: cryptSetAttribute()",
774  status, __LINE__ ) );
775 
776  /* Tell the client that we're ready to go */
777  releaseMutex();
778 
779  /* Activate the session */
780  status = activatePersistentServerSession( cryptSession, FALSE );
781  if( cryptStatusError( status ) )
782  {
783  cryptKeysetClose( cryptCertStore );
784  cryptDestroyContext( cryptCAKey );
785  return( extErrorExit( cryptSession, "SVR: Attempt to activate SCEP "
786  "server session", status, __LINE__ ) );
787  }
788 
789  /* Clean up */
790  cryptDestroySession( cryptSession );
791  cryptKeysetClose( cryptCertStore );
792  cryptDestroyContext( cryptCAKey );
793 
794  puts( "SVR: SCEP session succeeded.\n" );
795  return( TRUE );
796  }
797 
798 int testSessionSCEPServer( void )
799  {
800  int status;
801 
802  createMutex();
803  status = scepServer();
804  destroyMutex();
805 
806  return( status );
807  }
808 
809 /* Perform a client/server loopback test */
810 
811 #ifdef WINDOWS_THREADS
812 
813 unsigned __stdcall scepServerThread( void *dummy )
814  {
815  scepServer();
816  _endthreadex( 0 );
817  return( 0 );
818  }
819 
820 int testSessionSCEPClientServer( void )
821  {
822  HANDLE hThread;
823  unsigned threadID;
824  int status;
825 
826 #if ( SCEP_NO != 1 )
827  /* Because the code has to handle so many CA-specific peculiarities, we
828  can only perform this test when the CA being used is the cryptlib
829  CA */
830  puts( "Error: The local SCEP session test only works with SCEP_NO == 1." );
831  return( FALSE );
832 #endif /* cryptlib CA */
833 
834  /* Start the server and wait for it to initialise */
835  createMutex();
836  hThread = ( HANDLE ) _beginthreadex( NULL, 0, scepServerThread,
837  NULL, 0, &threadID );
838  Sleep( 1000 );
839 
840  /* Connect to the local server */
841  status = connectSCEP( TRUE, TRUE );
842  waitForThread( hThread );
843  destroyMutex();
844  return( status );
845  }
846 
848  {
849  HANDLE hThread;
850  unsigned threadID;
851  int value, status;
852 
853 #if ( SCEP_NO != 1 )
854  /* Because the code has to handle so many CA-specific peculiarities, we
855  can only perform this test when the CA being used is the cryptlib
856  CA */
857  puts( "Error: The local SCEP session test only works with SCEP_NO == 1." );
858  return( FALSE );
859 #endif /* cryptlib CA */
860 
861  /* Switch the hash algorithm to SHA-2 */
864  CRYPT_ALGO_SHA2 );
865 
866  /* Start the server and wait for it to initialise */
867  createMutex();
868  hThread = ( HANDLE ) _beginthreadex( NULL, 0, scepServerThread,
869  NULL, 0, &threadID );
870  Sleep( 1000 );
871 
872  /* Connect to the local server */
873  status = connectSCEP( TRUE, TRUE );
874  waitForThread( hThread );
875  destroyMutex();
877 
878  return( status );
879  }
880 
882  {
883  HANDLE hThread;
884  unsigned threadID;
885  int status;
886 
887 #if ( SCEP_NO != 1 )
888  /* Because the code has to handle so many CA-specific peculiarities, we
889  can only perform this test when the CA being used is the cryptlib
890  CA */
891  puts( "Error: The local SCEP session test only works with SCEP_NO == 1." );
892  return( FALSE );
893 #endif /* cryptlib CA */
894 
895  /* Start the server and wait for it to initialise */
896  createMutex();
897  hThread = ( HANDLE ) _beginthreadex( NULL, 0, scepServerThread,
898  NULL, 0, &threadID );
899  Sleep( 1000 );
900 
901  /* Connect to the local server */
902  status = connectSCEP( TRUE, FALSE );
903  waitForThread( hThread );
904  destroyMutex();
905  return( status );
906  }
907 #endif /* WINDOWS_THREADS */
908 
909 #endif /* TEST_SESSION || TEST_SESSION_LOOPBACK */