cryptlib  3.4.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros
sreqresp.c
Go to the documentation of this file.
1 /****************************************************************************
2 * *
3 * cryptlib Request/Response Session Test Routines *
4 * Copyright Peter Gutmann 1998-2008 *
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 /* Prototypes for functions in testcert.c */
20 
21 int initRTCS( CRYPT_CERTIFICATE *cryptRTCSRequest,
22  const CRYPT_CERTIFICATE cryptCertificateTemplate,
23  const int number, const BOOLEAN multipleCerts );
24 int initOCSP( CRYPT_CERTIFICATE *cryptOCSPRequest, const int number,
25  const BOOLEAN ocspv2, const BOOLEAN revokedCert,
26  const BOOLEAN multipleCerts,
27  const CRYPT_SIGNATURELEVEL_TYPE sigLevel,
28  const CRYPT_CONTEXT privKeyContext );
29 
30 #if defined( TEST_SESSION ) || defined( TEST_SESSION_LOOPBACK )
31 
32 /****************************************************************************
33 * *
34 * HTTP Certstore Routines Test *
35 * *
36 ****************************************************************************/
37 
38 /* This isn't really a proper session but just an HTTP certificate store
39  interface, but the semantics for the server side fit the session
40  interface better than the keyset interface */
41 
42 static int connectCertstoreServer( void )
43  {
44  CRYPT_SESSION cryptSession;
45  CRYPT_KEYSET cryptCertStore;
46  int connectionActive, status;
47 
48  puts( "Testing HTTP certstore server session..." );
49 
50  /* Create the HTTP certstore session */
51  status = cryptCreateSession( &cryptSession, CRYPT_UNUSED,
53  if( status == CRYPT_ERROR_PARAM3 ) /* Certstore session access not available */
54  return( CRYPT_ERROR_NOTAVAIL );
55  if( cryptStatusError( status ) )
56  {
57  printf( "cryptCreateSession() failed with error code %d, line %d.\n",
58  status, __LINE__ );
59  return( FALSE );
60  }
61  if( !setLocalConnect( cryptSession, 80 ) )
62  return( FALSE );
63 
64  /* Add the certificate store that we'll be using to provide certs (it's
65  actually just the generic database keyset and not the full
66  certificate store, because this contains more test certs) */
67  status = cryptKeysetOpen( &cryptCertStore, CRYPT_UNUSED,
70  if( status == CRYPT_ERROR_PARAM3 )
71  {
72  /* This type of keyset access isn't available, return a special
73  error code to indicate that the test wasn't performed, but
74  that this isn't a reason to abort processing */
75  puts( "SVR: No certificate store available, aborting HTTP certstore "
76  "responder test.\n" );
77  cryptDestroySession( cryptSession );
78  return( CRYPT_ERROR_NOTAVAIL );
79  }
80  if( cryptStatusOK( status ) )
81  {
82  status = cryptSetAttribute( cryptSession,
83  CRYPT_SESSINFO_KEYSET, cryptCertStore );
84  cryptKeysetClose( cryptCertStore );
85  }
86  if( cryptStatusError( status ) )
87  return( attrErrorExit( cryptSession, "SVR: cryptSetAttribute()",
88  status, __LINE__ ) );
89 
90  /* Activate the server */
91  status = cryptSetAttribute( cryptSession, CRYPT_SESSINFO_ACTIVE, TRUE );
92  printConnectInfo( cryptSession );
93  if( cryptStatusError( status ) )
94  {
95  printExtError( cryptSession, "SVR: Attempt to activate HTTP "
96  "certstore server session", status, __LINE__ );
97  cryptDestroySession( cryptSession );
98  return( FALSE );
99  }
100 
101  /* Check whether the session connection is still open */
102  status = cryptGetAttribute( cryptSession, CRYPT_SESSINFO_CONNECTIONACTIVE,
103  &connectionActive );
104  if( cryptStatusError( status ) || !connectionActive )
105  {
106  printExtError( cryptSession, "SVR: Persistent connection has been "
107  "closed, operation", status, __LINE__ );
108  return( FALSE );
109  }
110 
111  /* Activate the connection to handle two more requests */
112  status = cryptSetAttribute( cryptSession, CRYPT_SESSINFO_ACTIVE, TRUE );
113  if( cryptStatusError( status ) )
114  {
115  printExtError( cryptSession, "SVR: Attempt to perform second HTTP "
116  "certstore server transaction", status, __LINE__ );
117  cryptDestroySession( cryptSession );
118  return( status );
119  }
120  status = cryptSetAttribute( cryptSession, CRYPT_SESSINFO_ACTIVE, TRUE );
121  if( cryptStatusError( status ) )
122  {
123  printExtError( cryptSession, "SVR: Attempt to perform third HTTP "
124  "certstore server transaction", status, __LINE__ );
125  cryptDestroySession( cryptSession );
126  return( status );
127  }
128 
129  /* Clean up */
130  status = cryptDestroySession( cryptSession );
131  if( cryptStatusError( status ) )
132  {
133  printf( "cryptDestroySession() failed with error code %d, line %d.\n",
134  status, __LINE__ );
135  return( FALSE );
136  }
137 
138  puts( "SVR: HTTP certstore server session succeeded.\n" );
139  return( TRUE );
140  }
141 
142 static int connectCertstoreClient( void )
143  {
144  CRYPT_KEYSET cryptKeyset;
145  CRYPT_CERTIFICATE cryptCert;
146  const C_STR cert1ID = TEXT( "[email protected]" );
147  const C_STR cert2ID = TEXT( "[email protected]" );
148  int status;
149 
150  /* Open the keyset with a check to make sure this access method exists
151  so we can return an appropriate error message */
152  status = cryptKeysetOpen( &cryptKeyset, CRYPT_UNUSED, CRYPT_KEYSET_HTTP,
153  TEXT( "localhost" ), CRYPT_KEYOPT_READONLY );
154  if( status == CRYPT_ERROR_PARAM3 )
155  {
156  /* This type of keyset access not available */
157  return( CRYPT_ERROR_NOTAVAIL );
158  }
159  if( cryptStatusError( status ) )
160  {
161  printf( "cryptKeysetOpen() failed with error code %d, line %d.\n",
162  status, __LINE__ );
163  return( CRYPT_ERROR_FAILED );
164  }
165 
166 
167  /* Read a present certificate from the keyset using the ASCII email
168  address */
169  status = cryptGetPublicKey( cryptKeyset, &cryptCert, CRYPT_KEYID_EMAIL,
170  cert1ID );
171  if( cryptStatusError( status ) )
172  return( extErrorExit( cryptKeyset, "cryptGetPublicKey()", status,
173  __LINE__ ) );
174  printf( "Successfully read certificate for '%s'.\n", cert1ID );
175  cryptDestroyCert( cryptCert );
176 
177  /* Read a non-present certificate from the keyset */
178  status = cryptGetPublicKey( cryptKeyset, &cryptCert, CRYPT_KEYID_EMAIL,
179  cert2ID );
180  if( status == CRYPT_ERROR_NOTFOUND )
181  printf( "Successfully processed not-present code for '%s'.\n",
182  cert2ID );
183  else
184  return( extErrorExit( cryptKeyset, "cryptGetPublicKey()", status,
185  __LINE__ ) );
186 
187  /* Read the certificate from the keyset using the base64-encoded certID.
188  Since this uses an internal identifier, we can't actually do it from
189  here, this requires modifying the internal keyset read code to
190  substitute the different identifier type.
191 
192  A second purpose for this call is to test the ability of the client
193  to recover from the CRYPT_ERROR_NOTFOUND in the previous call, i.e.
194  the error should be nonfatal with further requests possible */
195  status = cryptGetPublicKey( cryptKeyset, &cryptCert, CRYPT_KEYID_EMAIL,
196  cert1ID );
197  if( cryptStatusError( status ) )
198  return( extErrorExit( cryptKeyset, "cryptGetPublicKey()", status,
199  __LINE__ ) );
200  printf( "Successfully read certificate for '%s'.\n", cert1ID );
201  cryptDestroyCert( cryptCert );
202 
203  /* Clean up */
204  cryptKeysetClose( cryptKeyset );
205  return( TRUE );
206  }
207 
209  {
210  return( connectCertstoreServer() );
211  }
212 
213 /* Perform a client/server loopback test */
214 
215 #ifdef WINDOWS_THREADS
216 
217 unsigned __stdcall certstoreServerThread( void *dummy )
218  {
219  connectCertstoreServer();
220  _endthreadex( 0 );
221  return( 0 );
222  }
223 
225  {
226  HANDLE hThread;
227  unsigned threadID;
228  int status;
229 
230  /* Start the server and wait for it to initialise */
231  createMutex();
232  hThread = ( HANDLE ) _beginthreadex( NULL, 0, certstoreServerThread,
233  NULL, 0, &threadID );
234  Sleep( 1000 );
235 
236  /* Connect to the local server */
237  status = connectCertstoreClient();
238  waitForThread( hThread );
239  destroyMutex();
240  return( status );
241  }
242 #endif /* WINDOWS_THREADS */
243 
244 /****************************************************************************
245 * *
246 * RTCS Routines Test *
247 * *
248 ****************************************************************************/
249 
250 /* There are various test RTCS servers running, the following remapping
251  allows us to switch between them. Implementation peculiarities:
252 
253  #1 - cryptlib:
254  None */
255 
256 #define RTCS_SERVER_NO 1
257 #if RTCS_SERVER_NO == 1
258  #define RTCS_SERVER_NAME TEXT( "http://localhost" )
259 #endif /* RTCS server name kludge */
260 
261 /* Perform an RTCS test */
262 
263 static int connectRTCS( const CRYPT_SESSION_TYPE sessionType,
264  const BOOLEAN multipleCerts,
265  const BOOLEAN localSession )
266  {
267  CRYPT_SESSION cryptSession;
268  CRYPT_CERTIFICATE cryptRTCSRequest;
269  char filenameBuffer[ FILENAME_BUFFER_SIZE ];
270 #ifdef UNICODE_STRINGS
271  wchar_t wcBuffer[ FILENAME_BUFFER_SIZE ];
272 #endif /* UNICODE_STRINGS */
273  void *fileNamePtr = filenameBuffer;
274  const BOOLEAN isServer = ( sessionType == CRYPT_SESSION_RTCS_SERVER ) ? \
275  TRUE : FALSE;
276  int status;
277 
278  printf( "%sTesting %sRTCS session...\n", isServer ? "SVR: " : "",
279  localSession ? "local " : "" );
280 
281  /* If we're the client, wait for the server to finish initialising */
282  if( localSession && !isServer && waitMutex() == CRYPT_ERROR_TIMEOUT )
283  {
284  printf( "Timed out waiting for server to initialise, line %d.\n",
285  __LINE__ );
286  return( FALSE );
287  }
288 
289  /* Create the RTCS session */
290  status = cryptCreateSession( &cryptSession, CRYPT_UNUSED, sessionType );
291  if( status == CRYPT_ERROR_PARAM3 ) /* RTCS session access not available */
292  return( CRYPT_ERROR_NOTAVAIL );
293  if( cryptStatusError( status ) )
294  {
295  printf( "cryptCreateSession() failed with error code %d, line %d.\n",
296  status, __LINE__ );
297  return( FALSE );
298  }
299  if( isServer )
300  {
301  CRYPT_CONTEXT cryptPrivateKey;
302  CRYPT_KEYSET cryptCertStore;
303 
304  if( !setLocalConnect( cryptSession, 80 ) )
305  return( FALSE );
306 
307  /* Add the responder private key */
309 #ifdef UNICODE_STRINGS
310  mbstowcs( wcBuffer, filenameBuffer, strlen( filenameBuffer ) + 1 );
311  fileNamePtr = wcBuffer;
312 #endif /* UNICODE_STRINGS */
313  status = getPrivateKey( &cryptPrivateKey, fileNamePtr,
315  if( cryptStatusOK( status ) )
316  {
317  status = cryptSetAttribute( cryptSession,
318  CRYPT_SESSINFO_PRIVATEKEY, cryptPrivateKey );
319  cryptDestroyContext( cryptPrivateKey );
320  }
321  if( cryptStatusError( status ) )
322  return( attrErrorExit( cryptSession, "SVR: cryptSetAttribute()",
323  status, __LINE__ ) );
324 
325  /* Add the certificate store that we'll be using to provide
326  revocation information */
327  status = cryptKeysetOpen( &cryptCertStore, CRYPT_UNUSED,
330  if( status == CRYPT_ERROR_PARAM3 )
331  {
332  /* This type of keyset access isn't available, return a special
333  error code to indicate that the test wasn't performed, but
334  that this isn't a reason to abort processing */
335  puts( "SVR: No certificate store available, aborting RTCS "
336  "responder test.\n" );
337  cryptDestroySession( cryptSession );
338  return( CRYPT_ERROR_NOTAVAIL );
339  }
340  if( status == CRYPT_ERROR_OPEN )
341  {
342  /* The keyset is available, but it hasn't been created yet by an
343  earlier self-test, this isn't a reason to abort processing */
344  puts( "SVR: Certificate store hasn't been created yet by "
345  "earlier tests, aborting\n RTCS responder test.\n" );
346  cryptDestroySession( cryptSession );
347  return( CRYPT_ERROR_NOTAVAIL );
348  }
349  if( cryptStatusOK( status ) )
350  {
351  status = cryptSetAttribute( cryptSession,
352  CRYPT_SESSINFO_KEYSET, cryptCertStore );
353  cryptKeysetClose( cryptCertStore );
354  }
355  if( cryptStatusError( status ) )
356  return( attrErrorExit( cryptSession, "SVR: cryptSetAttribute()",
357  status, __LINE__ ) );
358 
359  /* Tell the client that we're ready to go */
360  if( localSession )
361  releaseMutex();
362  }
363  else
364  {
365  CRYPT_KEYSET cryptKeyset;
366  CRYPT_CERTIFICATE cryptCert = DUMMY_INIT;
367 
368  /* Get the certificate whose status we're checking */
369  status = cryptKeysetOpen( &cryptKeyset, CRYPT_UNUSED,
372  if( cryptStatusOK( status ) )
373  {
374  status = cryptGetPublicKey( cryptKeyset, &cryptCert,
376  TEXT( "Test user 1" ) );
377  cryptKeysetClose( cryptKeyset );
378  }
379  if( cryptStatusError( status ) )
380  {
381  printf( "Couldn't read certificate for RTCS status check, error "
382  "code %d, line %d.\n", status, __LINE__ );
383  return( FALSE );
384  }
385 
386  /* Create the RTCS request */
387  if( !initRTCS( &cryptRTCSRequest, cryptCert, localSession ? \
388  1 : RTCS_SERVER_NO, multipleCerts ) )
389  return( FALSE );
390  cryptDestroyCert( cryptCert );
391 
392  /* Set up the server information and activate the session. In
393  theory the RTCS request will contain all the information needed
394  for the session so there'd be nothing else to add before we
395  activate it, however many certs contain incorrect server URLs so
396  we set the server name manually if necessary, overriding the
397  value present in the RTCS request (via the certificate) */
398  status = cryptSetAttribute( cryptSession, CRYPT_SESSINFO_REQUEST,
399  cryptRTCSRequest );
400  if( cryptStatusError( status ) )
401  return( attrErrorExit( cryptSession, "cryptSetAttribute()",
402  status, __LINE__ ) );
403  cryptDestroyCert( cryptRTCSRequest );
404  if( localSession && !setLocalConnect( cryptSession, 80 ) )
405  return( FALSE );
406 #ifdef RTCS_SERVER_NAME
407  if( !localSession )
408  {
409  printf( "Setting RTCS server to %s.\n", RTCS_SERVER_NAME );
411  status = cryptSetAttributeString( cryptSession,
412  CRYPT_SESSINFO_SERVER_NAME, RTCS_SERVER_NAME,
413  paramStrlen( RTCS_SERVER_NAME ) );
414  if( cryptStatusError( status ) )
415  return( attrErrorExit( cryptSession,
416  "cryptSetAttributeString()", status,
417  __LINE__ ) );
418  }
419 #endif /* Kludges for incorrect/missing authorityInfoAccess values */
420 
421  /* Wait for the server to finish initialising */
422  if( localSession && waitMutex() == CRYPT_ERROR_TIMEOUT )
423  {
424  printf( "Timed out waiting for server to initialise, line %d.\n",
425  __LINE__ );
426  return( FALSE );
427  }
428  }
429  status = cryptSetAttribute( cryptSession, CRYPT_SESSINFO_ACTIVE, TRUE );
430  if( isServer )
431  printConnectInfo( cryptSession );
432  if( cryptStatusError( status ) )
433  {
434  printExtError( cryptSession, isServer ? \
435  "SVR: Attempt to activate RTCS server session" : \
436  "Attempt to activate RTCS client session", status,
437  __LINE__ );
438  cryptDestroySession( cryptSession );
439  if( status == CRYPT_ERROR_OPEN || status == CRYPT_ERROR_NOTFOUND || \
440  status == CRYPT_ERROR_TIMEOUT || status == CRYPT_ERROR_PERMISSION )
441  {
442  /* These servers are constantly appearing and disappearing so if
443  we get a straight connect error we don't treat it as a serious
444  failure. In addition we can get server busy and no permission
445  to access errors that are also treated as soft errors */
446  puts( " (Server could be down or busy or unavailable, faking it "
447  "and continuing...)\n" );
448  return( CRYPT_ERROR_FAILED );
449  }
450  return( FALSE );
451  }
452 
453  /* Obtain the response information */
454  if( !isServer )
455  {
456  CRYPT_CERTIFICATE cryptRTCSResponse;
457 
458  status = cryptGetAttribute( cryptSession, CRYPT_SESSINFO_RESPONSE,
459  &cryptRTCSResponse );
460  if( cryptStatusError( status ) )
461  {
462  printf( "cryptGetAttribute() failed with error code %d, line "
463  "%d.\n", status, __LINE__ );
464  return( FALSE );
465  }
466  printCertInfo( cryptRTCSResponse );
467  cryptDestroyCert( cryptRTCSResponse );
468  }
469 
470  /* Clean up */
471  status = cryptDestroySession( cryptSession );
472  if( cryptStatusError( status ) )
473  {
474  printf( "cryptDestroySession() failed with error code %d, line %d.\n",
475  status, __LINE__ );
476  return( FALSE );
477  }
478 
479  puts( isServer ? "SVR: RTCS server session succeeded.\n" : \
480  "RTCS client session succeeded.\n" );
481  return( TRUE );
482  }
483 
484 static int connectRTCSDirect( void )
485  {
486  CRYPT_CERTIFICATE cryptCert;
487  CRYPT_SESSION cryptSession;
488  int status;
489 
490  printf( "Testing direct RTCS query...\n" );
491 
492  /* Get the EE certificate */
493  status = importCertFromTemplate( &cryptCert, RTCS_FILE_TEMPLATE,
494  RTCS_SERVER_NO );
495  if( cryptStatusError( status ) )
496  {
497  printf( "EE cryptImportCert() failed with error code %d, line %d.\n",
498  status, __LINE__ );
499  return( FALSE );
500  }
501 
502  /* Create the RTCS session and add the server URL */
503  status = cryptCreateSession( &cryptSession, CRYPT_UNUSED,
505  if( status == CRYPT_ERROR_PARAM3 ) /* RTCS session access not available */
506  return( CRYPT_ERROR_NOTAVAIL );
507 #ifdef RTCS_SERVER_NAME
508  status = cryptSetAttributeString( cryptSession,
509  CRYPT_SESSINFO_SERVER_NAME, RTCS_SERVER_NAME,
510  paramStrlen( RTCS_SERVER_NAME ) );
511  if( cryptStatusError( status ) )
512  return( attrErrorExit( cryptSession, "cryptSetAttributeString()",
513  status, __LINE__ ) );
514 #endif /* Kludges for incorrect/missing authorityInfoAccess values */
515 
516  /* Check the certificate directly against the server */
517  status = cryptCheckCert( cryptCert, cryptSession );
518  printf( "Certificate status check returned %d.\n", status );
519 
520  /* Clean up */
521  cryptDestroyCert( cryptCert );
522  cryptDestroySession( cryptSession );
523 
524  puts( "RTCS direct query succeeded.\n" );
525  return( TRUE );
526  }
527 
528 int testSessionRTCS( void )
529  {
530  if( !connectRTCS( CRYPT_SESSION_RTCS, FALSE, FALSE ) )
531  return( FALSE );
532  if( !connectRTCSDirect() )
533  return( FALSE );
534 #if RTCS_SERVER_NO == 1
535  return( connectRTCS( CRYPT_SESSION_RTCS, TRUE, FALSE ) );
536 #else
537  return( TRUE );
538 #endif /* Server that has a revoked certificate */
539  }
540 int testSessionRTCSServer( void )
541  {
542  int status;
543 
544  createMutex();
545  acquireMutex();
546  status = connectRTCS( CRYPT_SESSION_RTCS_SERVER, FALSE, FALSE );
547  destroyMutex();
548 
549  return( status );
550  }
551 
552 /* Perform a client/server loopback test */
553 
554 #ifdef WINDOWS_THREADS
555 
556 unsigned __stdcall rtcsServerThread( void *dummy )
557  {
558  acquireMutex();
559  connectRTCS( CRYPT_SESSION_RTCS_SERVER, FALSE, TRUE );
560  _endthreadex( 0 );
561  return( 0 );
562  }
563 
564 int testSessionRTCSClientServer( void )
565  {
566  HANDLE hThread;
567  unsigned threadID;
568  int status;
569 
570  /* Start the server and wait for it to initialise */
571  createMutex();
572  hThread = ( HANDLE ) _beginthreadex( NULL, 0, rtcsServerThread,
573  NULL, 0, &threadID );
574  Sleep( 2000 );
575 
576  /* Connect to the local server */
577  status = connectRTCS( CRYPT_SESSION_RTCS, FALSE, TRUE );
578  waitForThread( hThread );
579  destroyMutex();
580  return( status );
581  }
582 #endif /* WINDOWS_THREADS */
583 
584 /****************************************************************************
585 * *
586 * OCSP Routines Test *
587 * *
588 ****************************************************************************/
589 
590 /* There are various test OCSP servers running, the following remapping
591  allows us to switch between them. Implementation peculiarities:
592 
593  #1 - cryptlib:
594  None
595  #2 - iD2 aka SmartTrust
596  AuthorityInfoAccess doesn't match the real server URL, requires
597  the SmartTrust server name below to override the AIA value.
598  Currently not active.
599  #3 - Identrus aka Xetex:
600  AuthorityInfoAccess doesn't match the real server URL, requires
601  the Xetex server name below to override the AIA value. Currently
602  not active.
603  #4 - Thawte aka Valicert
604  No AuthorityInfoAccess, requires the Valicert server name below
605  to provide a server. Since all Thawte CA certs are invalid (no
606  keyUsage, meaning they're non-CA certs) cryptlib will reject them
607  for OCSPv1 queries.
608  #5 - Verisign
609  No AuthorityInfoAccess, requires the Verisign server name below
610  to provide a server.
611  #6 - Diginotar
612  Have an invalid CA certificate, and (apparently) a broken OCSP
613  implementation that gets the IDs wrong (this is par for the
614  course for this particular CA) */
615 
616 #define OCSP_SERVER_NO 5
617 #if OCSP_SERVER_NO == 2
618  #define OCSP_SERVER_NAME TEXT( "http://ocsp.smarttrust.com:82/ocsp" )
619 #elif OCSP_SERVER_NO == 3
620  #define OCSP_SERVER_NAME TEXT( "http://ocsp.xetex.com:8080/servlet/ocsp" )
621 #elif OCSP_SERVER_NO == 4
622  #define OCSP_SERVER_NAME TEXT( "http://ocsp2.valicert.net" )
623 #elif OCSP_SERVER_NO == 5
624  #define OCSP_SERVER_NAME TEXT( "http://ocsp.verisign.com/ocsp/status" )
625 #endif /* OCSP server name kludge */
626 
627 /* Perform an OCSP test */
628 
629 static int connectOCSP( const CRYPT_SESSION_TYPE sessionType,
630  const BOOLEAN revokedCert,
631  const BOOLEAN multipleCerts,
632  const BOOLEAN localSession )
633  {
634  CRYPT_SESSION cryptSession;
635  CRYPT_CERTIFICATE cryptOCSPRequest;
636  char filenameBuffer[ FILENAME_BUFFER_SIZE ];
637 #ifdef UNICODE_STRINGS
638  wchar_t wcBuffer[ FILENAME_BUFFER_SIZE ];
639 #endif /* UNICODE_STRINGS */
640  void *fileNamePtr = filenameBuffer;
641  const BOOLEAN isServer = ( sessionType == CRYPT_SESSION_OCSP_SERVER ) ? \
642  TRUE : FALSE;
643  int status;
644 
645  printf( "%sTesting %sOCSP session...\n", isServer ? "SVR: " : "",
646  localSession ? "local " : "" );
647 
648  /* If we're the client, wait for the server to finish initialising */
649  if( localSession && !isServer && waitMutex() == CRYPT_ERROR_TIMEOUT )
650  {
651  printf( "Timed out waiting for server to initialise, line %d.\n",
652  __LINE__ );
653  return( FALSE );
654  }
655 
656  /* Create the OCSP session */
657  status = cryptCreateSession( &cryptSession, CRYPT_UNUSED, sessionType );
658  if( status == CRYPT_ERROR_PARAM3 ) /* OCSP session access not available */
659  return( CRYPT_ERROR_NOTAVAIL );
660  if( cryptStatusError( status ) )
661  {
662  printf( "cryptCreateSession() failed with error code %d, line %d.\n",
663  status, __LINE__ );
664  return( FALSE );
665  }
666  if( isServer )
667  {
668  CRYPT_CONTEXT cryptPrivateKey;
669  CRYPT_KEYSET cryptCertStore;
670 
671  if( !setLocalConnect( cryptSession, 80 ) )
672  return( FALSE );
673 
674  /* Add the responder private key */
676 #ifdef UNICODE_STRINGS
677  mbstowcs( wcBuffer, filenameBuffer, strlen( filenameBuffer ) + 1 );
678  fileNamePtr = wcBuffer;
679 #endif /* UNICODE_STRINGS */
680  status = getPrivateKey( &cryptPrivateKey, fileNamePtr,
682  if( cryptStatusOK( status ) )
683  {
684  status = cryptSetAttribute( cryptSession,
685  CRYPT_SESSINFO_PRIVATEKEY, cryptPrivateKey );
686  cryptDestroyContext( cryptPrivateKey );
687  }
688  if( cryptStatusError( status ) )
689  return( attrErrorExit( cryptSession, "SVR: cryptSetAttribute()",
690  status, __LINE__ ) );
691 
692  /* Add the certificate store that we'll be using to provide
693  revocation information */
694  status = cryptKeysetOpen( &cryptCertStore, CRYPT_UNUSED,
697  if( status == CRYPT_ERROR_PARAM3 )
698  {
699  /* This type of keyset access isn't available, return a special
700  error code to indicate that the test wasn't performed, but
701  that this isn't a reason to abort processing */
702  puts( "SVR: No certificate store available, aborting OCSP "
703  "responder test.\n" );
704  cryptDestroySession( cryptSession );
705  return( CRYPT_ERROR_NOTAVAIL );
706  }
707  if( cryptStatusOK( status ) )
708  {
709  status = cryptSetAttribute( cryptSession,
710  CRYPT_SESSINFO_KEYSET, cryptCertStore );
711  cryptKeysetClose( cryptCertStore );
712  }
713  if( cryptStatusError( status ) )
714  return( attrErrorExit( cryptSession, "SVR: cryptSetAttribute()",
715  status, __LINE__ ) );
716 
717  /* Tell the client that we're ready to go */
718  if( localSession )
719  releaseMutex();
720  }
721  else
722  {
723  /* Create the OCSP request */
724  if( !initOCSP( &cryptOCSPRequest, localSession ? 1 : OCSP_SERVER_NO,
725  FALSE, revokedCert, multipleCerts,
727  return( FALSE );
728 
729  /* Set up the server information and activate the session. In
730  theory the OCSP request will contain all the information needed
731  for the session so there'd be nothing else to add before we
732  activate it, however many certs contain incorrect server URLs so
733  we set the server name manually if necessary, overriding the
734  value present in the OCSP request (via the certificate) */
735  status = cryptSetAttribute( cryptSession, CRYPT_SESSINFO_REQUEST,
736  cryptOCSPRequest );
737  if( cryptStatusError( status ) )
738  return( attrErrorExit( cryptSession, "cryptSetAttribute()",
739  status, __LINE__ ) );
740  cryptDestroyCert( cryptOCSPRequest );
741  if( localSession && !setLocalConnect( cryptSession, 80 ) )
742  return( FALSE );
743 #ifdef OCSP_SERVER_NAME
744  if( !localSession )
745  {
746  printf( "Setting OCSP server to %s.\n", OCSP_SERVER_NAME );
748  status = cryptSetAttributeString( cryptSession,
749  CRYPT_SESSINFO_SERVER_NAME, OCSP_SERVER_NAME,
750  paramStrlen( OCSP_SERVER_NAME ) );
751  if( cryptStatusError( status ) )
752  return( attrErrorExit( cryptSession,
753  "cryptSetAttributeString()", status,
754  __LINE__ ) );
755  }
756 #endif /* Kludges for incorrect/missing authorityInfoAccess values */
757  if( OCSP_SERVER_NO == 1 || localSession )
758  {
759  /* The cryptlib server doesn't handle the weird v1 certIDs */
760  status = cryptSetAttribute( cryptSession, CRYPT_SESSINFO_VERSION,
761  2 );
762  if( cryptStatusError( status ) )
763  return( attrErrorExit( cryptSession, "cryptSetAttribute()",
764  status, __LINE__ ) );
765  }
766 
767  /* Wait for the server to finish initialising */
768  if( localSession && waitMutex() == CRYPT_ERROR_TIMEOUT )
769  {
770  printf( "Timed out waiting for server to initialise, line %d.\n",
771  __LINE__ );
772  return( FALSE );
773  }
774  }
775  status = cryptSetAttribute( cryptSession, CRYPT_SESSINFO_ACTIVE, TRUE );
776  if( isServer )
777  printConnectInfo( cryptSession );
778  if( cryptStatusError( status ) )
779  {
780  printExtError( cryptSession, isServer ? \
781  "SVR: Attempt to activate OCSP server session" : \
782  "Attempt to activate OCSP client session", status,
783  __LINE__ );
784 #if OCSP_SERVER_NO == 5
785  if( status == CRYPT_ERROR_SIGNATURE )
786  {
787  char errorMessage[ 512 ];
788  int errorMessageLength;
789 
790  status = cryptGetAttributeString( cryptSession,
792  errorMessage, &errorMessageLength );
793  if( cryptStatusOK( status ) && errorMessageLength >= 29 && \
794  !memcmp( errorMessage, "OCSP response doesn't contain", 29 ) )
795  {
796  cryptDestroySession( cryptSession );
797  puts( " (Verisign's OCSP responder sends broken responses, "
798  "continuing...)\n" );
799  return( CRYPT_ERROR_FAILED );
800  }
801  }
802 #endif /* Verisign's broken OCSP responder */
803  cryptDestroySession( cryptSession );
804  if( status == CRYPT_ERROR_OPEN || status == CRYPT_ERROR_NOTFOUND || \
805  status == CRYPT_ERROR_TIMEOUT || status == CRYPT_ERROR_PERMISSION )
806  {
807 
808  /* These servers are constantly appearing and disappearing so if
809  we get a straight connect error we don't treat it as a serious
810  failure. In addition we can get server busy and no permission
811  to access errors that are also treated as soft errors */
812  puts( " (Server could be down or busy or unavailable, faking it "
813  "and continuing...)\n" );
814  return( CRYPT_ERROR_FAILED );
815  }
816  return( FALSE );
817  }
818 
819  /* Obtain the response information */
820  if( !isServer )
821  {
822  CRYPT_CERTIFICATE cryptOCSPResponse;
823 
824  status = cryptGetAttribute( cryptSession, CRYPT_SESSINFO_RESPONSE,
825  &cryptOCSPResponse );
826  if( cryptStatusError( status ) )
827  {
828  printf( "cryptGetAttribute() failed with error code %d, line "
829  "%d.\n", status, __LINE__ );
830  return( FALSE );
831  }
832  printCertInfo( cryptOCSPResponse );
833  cryptDestroyCert( cryptOCSPResponse );
834  }
835 
836  /* There are so many weird ways to delegate trust and signing authority
837  mentioned in the OCSP RFC without any indication of which one
838  implementors will follow that we can't really perform any sort of
839  automated check since every responder seems to interpret this
840  differently, and many require manual installation of responder certs
841  in order to function */
842 #if 0
843  status = cryptCheckCert( cryptOCSPResponse , CRYPT_UNUSED );
844  if( cryptStatusError( status ) )
845  return( attrErrorExit( cryptOCSPResponse , "cryptCheckCert()",
846  status, __LINE__ ) );
847 #endif /* 0 */
848 
849  /* Clean up */
850  status = cryptDestroySession( cryptSession );
851  if( cryptStatusError( status ) )
852  {
853  printf( "cryptDestroySession() failed with error code %d, line %d.\n",
854  status, __LINE__ );
855  return( FALSE );
856  }
857 
858  puts( isServer ? "SVR: OCSP server session succeeded.\n" : \
859  "OCSP client session succeeded.\n" );
860  return( TRUE );
861  }
862 
863 static int connectOCSPDirect( void )
864  {
865  CRYPT_CERTIFICATE cryptCert;
866  CRYPT_SESSION cryptSession;
867  int status;
868 
869  printf( "Testing direct OCSP query...\n" );
870 
871  /* Get the EE certificate */
872  status = importCertFromTemplate( &cryptCert, OCSP_EEOK_FILE_TEMPLATE,
873  OCSP_SERVER_NO );
874  if( cryptStatusError( status ) )
875  {
876  printf( "EE cryptImportCert() failed with error code %d, line %d.\n",
877  status, __LINE__ );
878  return( FALSE );
879  }
880 
881  /* Create the OCSP session and add the server URL */
882  status = cryptCreateSession( &cryptSession, CRYPT_UNUSED,
884  if( status == CRYPT_ERROR_PARAM3 ) /* OCSP session access not available */
885  return( CRYPT_ERROR_NOTAVAIL );
886 #ifdef OCSP_SERVER_NAME
887  status = cryptSetAttributeString( cryptSession,
888  CRYPT_SESSINFO_SERVER_NAME, OCSP_SERVER_NAME,
889  paramStrlen( OCSP_SERVER_NAME ) );
890  if( cryptStatusError( status ) )
891  return( attrErrorExit( cryptSession, "cryptSetAttributeString()",
892  status, __LINE__ ) );
893 #endif /* Kludges for incorrect/missing authorityInfoAccess values */
894 
895  /* Check the certificate directly against the server. This check
896  quantises the result into a basic pass/fail that doesn't provide as
897  much detail as the low-level OCSP check, so it's not unusual to get
898  CRYPT_ERROR_INVALID whent he low-level check returns
899  CRYPT_OCSPSTATUS_UNKNOWN */
900  status = cryptCheckCert( cryptCert, cryptSession );
901  printf( "Certificate status check returned %d.\n", status );
902 
903  /* Clean up */
904  cryptDestroyCert( cryptCert );
905  cryptDestroySession( cryptSession );
906 
907  puts( "OCSP direct query succeeded.\n" );
908  return( TRUE );
909  }
910 
911 int testSessionOCSP( void )
912  {
913  if( !connectOCSP( CRYPT_SESSION_OCSP, FALSE, FALSE, FALSE ) )
914  return( FALSE );
915  if( !connectOCSPDirect() )
916  return( FALSE );
917 #if OCSP_SERVER_NO == 1
918  if( !( connectOCSP( CRYPT_SESSION_OCSP, TRUE, FALSE, FALSE ) ) )
919  return( FALSE );
920  return( connectOCSP( CRYPT_SESSION_OCSP, FALSE, TRUE, FALSE ) );
921 #else
922  return( TRUE );
923 #endif /* Server that has a revoked certificate */
924  }
925 int testSessionOCSPServer( void )
926  {
927  return( connectOCSP( CRYPT_SESSION_OCSP_SERVER, FALSE, FALSE, FALSE ) );
928  }
929 
930 /* Perform a client/server loopback test */
931 
932 #ifdef WINDOWS_THREADS
933 
934 unsigned __stdcall ocspServerThread( void *dummy )
935  {
936  acquireMutex();
937  connectOCSP( CRYPT_SESSION_OCSP_SERVER, FALSE, FALSE, TRUE );
938  _endthreadex( 0 );
939  return( 0 );
940  }
941 
942 int testSessionOCSPClientServer( void )
943  {
944  HANDLE hThread;
945  unsigned threadID;
946  int status;
947 
948  /* Start the server and wait for it to initialise */
949  createMutex();
950  hThread = ( HANDLE ) _beginthreadex( NULL, 0, ocspServerThread,
951  NULL, 0, &threadID );
952  Sleep( 1000 );
953 
954  /* Connect to the local server */
955  status = connectOCSP( CRYPT_SESSION_OCSP, FALSE, FALSE, TRUE );
956  waitForThread( hThread );
957  destroyMutex();
958  return( status );
959  }
960 #endif /* WINDOWS_THREADS */
961 
962 /****************************************************************************
963 * *
964 * TSP Routines Test *
965 * *
966 ****************************************************************************/
967 
968 /* There are various test TSP servers running, the following remapping allows
969  us to switch between them in the hope of finding at least one which is
970  actually working. Implementation peculiarities:
971 
972  #1 - cryptlib:
973  None.
974  #2 - Peter Sylvester
975  Requires Host: header even for HTTP 1.0.
976  #3 - Timeproof
977  None (currently not active).
978  #4 - Korea Mobile Payment Service
979  Currently not active.
980  #5 - IAIK Graz
981  Never been seen active.
982  #6 - Fst s.r.l.
983  Returns garbled TCP-socket-protocol header.
984  #7 - Datum
985  Almost never active
986  #8 - Chinese University of Hong Kong
987  None, info at http://www.e-timestamping.com/status.html.
988  #9 - SeMarket
989  None.
990  #10 - Entrust
991  None.
992  #11 - nCipher
993  Very slow TSP, requires extended read timeout to get response.
994  #12 - Comodo
995  None */
996 
997 #define TSP_SERVER1_NAME TEXT( "localhost" )
998 #define TSP_SERVER2_NAME TEXT( "http://timestamping.edelweb.fr/service/tsp" )
999 #define TSP_SERVER3_NAME TEXT( "tcp://test.timeproof.de" )
1000 #define TSP_SERVER4_NAME TEXT( "tcp://203.238.37.132:3318" )
1001 #define TSP_SERVER5_NAME TEXT( "tcp://neurath.iaik.at" )
1002 #define TSP_SERVER6_NAME TEXT( "tcp://ricerca.fst.it" )
1003 #define TSP_SERVER7_NAME TEXT( "tcp://tssdemo2.datum.com" )
1004 #define TSP_SERVER8_NAME TEXT( "tcp://ts2.itsc.cuhk.edu.hk:3318" )
1005 #define TSP_SERVER9_NAME TEXT( "tcp://80.81.104.150" )
1006 #define TSP_SERVER10_NAME TEXT( "http://vsinterop.entrust.com:7001/verificationserver/rfc3161timestamp" )
1007 #define TSP_SERVER11_NAME TEXT( "tcp://dse200.ncipher.com" )
1008 #define TSP_SERVER12_NAME TEXT( "http://timestamp.comodoca.com/rfc3161" )
1009 
1010 #define TSP_SERVER_NAME TSP_SERVER2_NAME
1011 #define TSP_SERVER_NO 2 /* Only used to identify slow-timeout server #11 */
1012 
1013 /* Perform a timestamping test */
1014 
1015 static int testTSP( const CRYPT_SESSION cryptSession,
1016  const BOOLEAN isServer,
1017  const BOOLEAN isRecycledConnection,
1018  const BOOLEAN useAltHash,
1019  const BOOLEAN localSession )
1020  {
1021  int status;
1022 
1023  /* If we're the client, wait for the server to finish initialising */
1024  if( localSession && !isServer && waitMutex() == CRYPT_ERROR_TIMEOUT )
1025  {
1026  printf( "Timed out waiting for server to initialise, line %d.\n",
1027  __LINE__ );
1028  return( FALSE );
1029  }
1030 
1031  /* If we're the client, create a message imprint to timestamp */
1032  if( !isServer )
1033  {
1035 
1036  /* Create the hash value to add to the TSP request */
1037  status = cryptCreateContext( &hashContext, CRYPT_UNUSED,
1038  useAltHash ? CRYPT_ALGO_SHA256 : \
1039  CRYPT_ALGO_SHA1 );
1040  if( cryptStatusError( status ) )
1041  return( FALSE );
1042  cryptEncrypt( hashContext, "12345678", 8 );
1043  cryptEncrypt( hashContext, "", 0 );
1044  if( isRecycledConnection )
1045  {
1046  /* If we're moving further data over an existing connection,
1047  delete the message imprint from the previous run */
1048  status = cryptDeleteAttribute( cryptSession,
1050  if( cryptStatusError( status ) )
1051  {
1052  printf( "cryptDeleteAttribute() failed with error code %d, "
1053  "line %d.\n", status, __LINE__ );
1054  return( FALSE );
1055  }
1056  }
1057  status = cryptSetAttribute( cryptSession,
1059  hashContext );
1060  if( cryptStatusError( status ) )
1061  {
1062  printf( "cryptSetAttribute() failed with error code %d, line "
1063  "%d.\n", status, __LINE__ );
1064  return( FALSE );
1065  }
1066  cryptDestroyContext( hashContext );
1067 
1068  /* If it's a local session, wait for the server to finish
1069  initialising */
1070  if( localSession && waitMutex() == CRYPT_ERROR_TIMEOUT )
1071  {
1072  printf( "Timed out waiting for server to initialise, line %d.\n",
1073  __LINE__ );
1074  return( FALSE );
1075  }
1076  }
1077  else
1078  {
1079  /* We're the server, if this is the first connect tell the client
1080  that we're ready to go */
1081  if( localSession && !isRecycledConnection )
1082  releaseMutex();
1083  }
1084 
1085  /* Activate the session and timestamp the message */
1086 #if TSP_SERVER_NO == 11
1087  cryptSetAttribute( cryptSession, CRYPT_OPTION_NET_READTIMEOUT, 30 );
1088 #endif /* Very slow TSP */
1089  status = cryptSetAttribute( cryptSession, CRYPT_SESSINFO_ACTIVE, TRUE );
1090  if( isServer )
1091  printConnectInfo( cryptSession );
1092  if( cryptStatusError( status ) )
1093  {
1094  printExtError( cryptSession, isServer ? \
1095  "SVR: Attempt to activate TSP server session" : \
1096  "Attempt to activate TSP client session", status,
1097  __LINE__ );
1098  cryptDestroySession( cryptSession );
1099  if( status == CRYPT_ERROR_OPEN || status == CRYPT_ERROR_NOTFOUND || \
1100  status == CRYPT_ERROR_TIMEOUT || status == CRYPT_ERROR_PERMISSION )
1101  {
1102  /* These servers are constantly appearing and disappearing so if
1103  we get a straight connect error we don't treat it as a serious
1104  failure. In addition we can get server busy and no permission
1105  to access errors that are also treated as soft errors */
1106  puts( " (Server could be down, faking it and continuing...)\n" );
1107  return( CRYPT_ERROR_FAILED );
1108  }
1109  return( FALSE );
1110  }
1111 
1112  /* There's not much more we can do in the client at this point since the
1113  TSP data is only used internally by cryptlib, OTOH if we get to here
1114  then we've received a valid response from the TSA so all is OK */
1115  if( !isServer )
1116  {
1117  CRYPT_ENVELOPE cryptEnvelope;
1118  BYTE buffer[ BUFFER_SIZE ];
1119  int bytesCopied;
1120 
1121  status = cryptGetAttribute( cryptSession, CRYPT_SESSINFO_RESPONSE,
1122  &cryptEnvelope );
1123  if( cryptStatusError( status ) )
1124  {
1125  printExtError( cryptSession, "Attempt to process returned "
1126  "timestamp", status, __LINE__ );
1127  return( FALSE );
1128  }
1129  status = cryptPopData( cryptEnvelope, buffer, BUFFER_SIZE,
1130  &bytesCopied );
1131  if( cryptStatusError( status ) )
1132  {
1133  printf( "cryptPopData() failed with error code %d, line %d.\n",
1134  status, __LINE__ );
1135  return( FALSE );
1136  }
1137  printf( "Timestamp data size = %d bytes.\n", bytesCopied );
1138  debugDump( "tstinfo", buffer, bytesCopied );
1139  cryptDestroyEnvelope( cryptEnvelope );
1140  }
1141 
1142  return( TRUE );
1143  }
1144 
1145 static int connectTSP( const CRYPT_SESSION_TYPE sessionType,
1146  const CRYPT_HANDLE externalCryptContext,
1147  const BOOLEAN persistentConnection,
1148  const BOOLEAN localSession )
1149  {
1150  CRYPT_SESSION cryptSession;
1151  const BOOLEAN isServer = ( sessionType == CRYPT_SESSION_TSP_SERVER ) ? \
1152  TRUE : FALSE;
1153  const BOOLEAN useAltHash = ( !isServer && 0 ) ? TRUE : FALSE;
1154  int status;
1155 
1156  printf( "%sTesting %sTSP session...\n", isServer ? "SVR: " : "",
1157  localSession ? "local " : "" );
1158 
1159  /* Acquire the init mutex if we're the server */
1160  if( localSession && isServer )
1161  waitMutex();
1162 
1163  /* Create the TSP session */
1164  status = cryptCreateSession( &cryptSession, CRYPT_UNUSED, sessionType );
1165  if( status == CRYPT_ERROR_PARAM3 ) /* TSP session access not available */
1166  return( CRYPT_ERROR_NOTAVAIL );
1167  if( cryptStatusError( status ) )
1168  {
1169  printf( "%scryptCreateSession() failed with error code %d, line "
1170  "%d.\n", isServer ? "SVR: " : "", status, __LINE__ );
1171  return( FALSE );
1172  }
1173 
1174  /* Set up the server information and activate the session. Since this
1175  test explicitly tests the ability to handle persistent connections,
1176  we don't use the general-purpose request/response server wrapper,
1177  which only uses persistent connections opportunistically */
1178  if( isServer )
1179  {
1180  CRYPT_CONTEXT privateKey = externalCryptContext;
1181 
1182  if( !setLocalConnect( cryptSession, 318 ) )
1183  return( FALSE );
1184  if( externalCryptContext == CRYPT_UNUSED )
1185  status = getPrivateKey( &privateKey, TSA_PRIVKEY_FILE,
1188  if( cryptStatusOK( status ) )
1189  {
1190  status = cryptSetAttribute( cryptSession,
1191  CRYPT_SESSINFO_PRIVATEKEY, privateKey );
1192  if( externalCryptContext == CRYPT_UNUSED )
1193  cryptDestroyContext( privateKey );
1194  }
1195  }
1196  else
1197  {
1198  if( localSession )
1199  {
1200  if( !setLocalConnect( cryptSession, 318 ) )
1201  return( FALSE );
1202  }
1203  else
1204  {
1205  status = cryptSetAttributeString( cryptSession,
1206  CRYPT_SESSINFO_SERVER_NAME, TSP_SERVER_NAME,
1207  paramStrlen( TSP_SERVER_NAME ) );
1208  }
1209  }
1210  if( cryptStatusError( status ) )
1211  {
1212  printf( "cryptSetAttribute/cryptSetAttributeString() failed with "
1213  "error code %d, line %d.\n", status, __LINE__ );
1214  return( FALSE );
1215  }
1216  status = testTSP( cryptSession, isServer, FALSE, useAltHash, localSession );
1217  if( status <= 0 )
1218  return( status );
1219 
1220  /* Check whether the session connection is still open */
1221  if( persistentConnection )
1222  {
1223  int connectionActive;
1224 
1225  status = cryptGetAttribute( cryptSession, CRYPT_SESSINFO_CONNECTIONACTIVE,
1226  &connectionActive );
1227  if( cryptStatusError( status ) || !connectionActive )
1228  {
1229  printExtError( cryptSession, isServer ? \
1230  "SVR: Persistent connection has been closed, "
1231  "operation" : \
1232  "Persistent connection has been closed, operation",
1233  status, __LINE__ );
1234  return( FALSE );
1235  }
1236 
1237  /* Activate the connection to handle two more requests */
1238  status = testTSP( cryptSession, isServer, TRUE, FALSE, FALSE );
1239  if( status <= 0 )
1240  return( status );
1241  status = testTSP( cryptSession, isServer, TRUE, FALSE, FALSE );
1242  if( status <= 0 )
1243  return( status );
1244  }
1245 
1246  /* Clean up */
1247  status = cryptDestroySession( cryptSession );
1248  if( cryptStatusError( status ) )
1249  {
1250  printf( "cryptDestroySession() failed with error code %d, line %d.\n",
1251  status, __LINE__ );
1252  return( FALSE );
1253  }
1254 
1255  printf( isServer ? "SVR: %sTSP server session succeeded.\n\n" : \
1256  "%sTSP client session succeeded.\n\n",
1257  persistentConnection ? "Persistent " : "" );
1258  return( TRUE );
1259  }
1260 
1261 int testSessionTSP( void )
1262  {
1263  return( connectTSP( CRYPT_SESSION_TSP, CRYPT_UNUSED, FALSE, FALSE ) );
1264  }
1265 int testSessionTSPServer( void )
1266  {
1267  return( connectTSP( CRYPT_SESSION_TSP_SERVER, CRYPT_UNUSED, FALSE, FALSE ) );
1268  }
1269 int testSessionTSPServerEx( const CRYPT_CONTEXT privKeyContext )
1270  {
1271  return( connectTSP( CRYPT_SESSION_TSP_SERVER, privKeyContext, FALSE, FALSE ) );
1272  }
1273 
1274 /* Perform a client/server loopback test */
1275 
1276 #ifdef WINDOWS_THREADS
1277 
1278 unsigned __stdcall tspServerThread( void *dummy )
1279  {
1280  acquireMutex();
1282  _endthreadex( 0 );
1283  return( 0 );
1284  }
1285 
1286 int testSessionTSPClientServer( void )
1287  {
1288  HANDLE hThread;
1289  unsigned threadID;
1290  int status;
1291 
1292  /* Start the server and wait for it to initialise */
1293  createMutex();
1294  hThread = ( HANDLE ) _beginthreadex( NULL, 0, tspServerThread,
1295  NULL, 0, &threadID );
1296  Sleep( 1000 );
1297 
1298  /* Connect to the local server */
1299  status = connectTSP( CRYPT_SESSION_TSP, CRYPT_UNUSED, FALSE, TRUE );
1300  waitForThread( hThread );
1301  destroyMutex();
1302  return( status );
1303  }
1304 
1305 unsigned __stdcall tspServerPersistentThread( void *dummy )
1306  {
1307  acquireMutex();
1309  _endthreadex( 0 );
1310  return( 0 );
1311  }
1312 
1314  {
1315  HANDLE hThread;
1316  unsigned threadID;
1317  int status;
1318 
1319  /* Start the server and wait for it to initialise */
1320  createMutex();
1321  hThread = ( HANDLE ) _beginthreadex( NULL, 0, tspServerPersistentThread,
1322  NULL, 0, &threadID );
1323  Sleep( 1000 );
1324 
1325  /* Connect to the local server */
1326  status = connectTSP( CRYPT_SESSION_TSP, CRYPT_UNUSED, TRUE, TRUE );
1327  waitForThread( hThread );
1328  destroyMutex();
1329  return( status );
1330  }
1331 #endif /* WINDOWS_THREADS */
1332 
1333 #endif /* TEST_SESSION || TEST_SESSION_LOOPBACK */