1 /****************************************************************************
2 *																			*
3 *				cryptlib Request/Response Session Test Routines				*
4 *						Copyright Peter Gutmann 1998-2011					*
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 certs.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,
25 			  CRYPT_CERTIFICATE *cert1, CRYPT_CERTIFICATE *cert2,
26 			  const int number, const BOOLEAN ocspv2,
27 			  const BOOLEAN revokedCert, const BOOLEAN multipleCerts,
28 			  const CRYPT_SIGNATURELEVEL_TYPE sigLevel,
29 			  const CRYPT_CONTEXT privKeyContext );
30 
31 #if defined( TEST_SESSION ) || defined( TEST_SESSION_LOOPBACK )
32 
33 /****************************************************************************
34 *																			*
35 *							HTTP Certstore Routines Test					*
36 *																			*
37 ****************************************************************************/
38 
39 /* This isn't really a proper session but just an HTTP certificate store
40    interface, but the semantics for the server side fit the session
41    interface better than the keyset interface */
42 
connectCertstoreServer(void)43 static int connectCertstoreServer( void )
44 	{
45 	CRYPT_SESSION cryptSession;
46 	CRYPT_KEYSET cryptCertStore;
47 	int connectionActive, status;
48 
49 	puts( "Testing HTTP certstore server session..." );
50 
51 	/* Create the HTTP certstore session */
52 	status = cryptCreateSession( &cryptSession, CRYPT_UNUSED,
53 								 CRYPT_SESSION_CERTSTORE_SERVER );
54 	if( status == CRYPT_ERROR_PARAM3 )	/* Certstore session access not available */
55 		return( CRYPT_ERROR_NOTAVAIL );
56 	if( cryptStatusError( status ) )
57 		{
58 		printf( "cryptCreateSession() failed with error code %d, line %d.\n",
59 				status, __LINE__ );
60 		return( FALSE );
61 		}
62 	if( !setLocalConnect( cryptSession, 80 ) )
63 		return( FALSE );
64 
65 	/* Add the certificate store that we'll be using to provide certs (it's
66 	   actually just the generic database keyset and not the full
67 	   certificate store, because this contains more test certs) */
68 	status = cryptKeysetOpen( &cryptCertStore, CRYPT_UNUSED,
69 							  DATABASE_KEYSET_TYPE, DATABASE_KEYSET_NAME,
70 							  CRYPT_KEYOPT_READONLY );
71 	if( status == CRYPT_ERROR_PARAM3 )
72 		{
73 		/* This type of keyset access isn't available, return a special
74 		   error code to indicate that the test wasn't performed, but
75 		   that this isn't a reason to abort processing */
76 		puts( "SVR: No certificate store available, aborting HTTP certstore "
77 				  "responder test.\n" );
78 		cryptDestroySession( cryptSession );
79 		return( CRYPT_ERROR_NOTAVAIL );
80 		}
81 	if( cryptStatusOK( status ) )
82 		{
83 		status = cryptSetAttribute( cryptSession,
84 						CRYPT_SESSINFO_KEYSET, cryptCertStore );
85 		cryptKeysetClose( cryptCertStore );
86 		}
87 	if( cryptStatusError( status ) )
88 		return( attrErrorExit( cryptSession, "SVR: cryptSetAttribute()",
89 							   status, __LINE__ ) );
90 
91 	/* Activate the server */
92 	status = cryptSetAttribute( cryptSession, CRYPT_SESSINFO_ACTIVE, TRUE );
93 	printConnectInfo( cryptSession );
94 	if( cryptStatusError( status ) )
95 		{
96 		printExtError( cryptSession, "SVR: Attempt to activate HTTP "
97 					   "certstore server session", status, __LINE__ );
98 		cryptDestroySession( cryptSession );
99 		return( FALSE );
100 		}
101 
102 	/* Check whether the session connection is still open */
103 	status = cryptGetAttribute( cryptSession, CRYPT_SESSINFO_CONNECTIONACTIVE,
104 								&connectionActive );
105 	if( cryptStatusError( status ) || !connectionActive )
106 		{
107 		printExtError( cryptSession, "SVR: Persistent connection has been "
108 					   "closed, operation", status, __LINE__ );
109 		return( FALSE );
110 		}
111 
112 	/* Activate the connection to handle two more requests */
113 	status = cryptSetAttribute( cryptSession, CRYPT_SESSINFO_ACTIVE, TRUE );
114 	if( cryptStatusError( status ) )
115 		{
116 		printExtError( cryptSession, "SVR: Attempt to perform second HTTP "
117 					   "certstore server transaction", status, __LINE__ );
118 		cryptDestroySession( cryptSession );
119 		return( status );
120 		}
121 	status = cryptSetAttribute( cryptSession, CRYPT_SESSINFO_ACTIVE, TRUE );
122 	if( cryptStatusError( status ) )
123 		{
124 		printExtError( cryptSession, "SVR: Attempt to perform third HTTP "
125 					   "certstore server transaction", status, __LINE__ );
126 		cryptDestroySession( cryptSession );
127 		return( status );
128 		}
129 
130 	/* Clean up */
131 	status = cryptDestroySession( cryptSession );
132 	if( cryptStatusError( status ) )
133 		{
134 		printf( "cryptDestroySession() failed with error code %d, line %d.\n",
135 				status, __LINE__ );
136 		return( FALSE );
137 		}
138 
139 	puts( "SVR: HTTP certstore server session succeeded.\n" );
140 	return( TRUE );
141 	}
142 
connectCertstoreClient(void)143 static int connectCertstoreClient( void )
144 	{
145 	CRYPT_KEYSET cryptKeyset;
146 	CRYPT_CERTIFICATE cryptCert;
147 	const C_STR cert1ID = TEXT( "dave@wetaburgers.com" );
148 	const C_STR cert2ID = TEXT( "notpresent@absent.com" );
149 	int status;
150 
151 	/* Open the keyset with a check to make sure this access method exists
152 	   so we can return an appropriate error message */
153 	status = cryptKeysetOpen( &cryptKeyset, CRYPT_UNUSED, CRYPT_KEYSET_HTTP,
154 							  TEXT( "localhost" ), CRYPT_KEYOPT_READONLY );
155 	if( status == CRYPT_ERROR_PARAM3 )
156 		{
157 		/* This type of keyset access not available */
158 		return( CRYPT_ERROR_NOTAVAIL );
159 		}
160 	if( cryptStatusError( status ) )
161 		{
162 		printf( "cryptKeysetOpen() failed with error code %d, line %d.\n",
163 				status, __LINE__ );
164 		return( CRYPT_ERROR_FAILED );
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 
testSessionHTTPCertstoreServer(void)208 int testSessionHTTPCertstoreServer( void )
209 	{
210 	return( connectCertstoreServer() );
211 	}
212 
213 /* Perform a client/server loopback test */
214 
215 #ifdef WINDOWS_THREADS
216 
certstoreServerThread(void * dummy)217 unsigned __stdcall certstoreServerThread( void *dummy )
218 	{
219 	connectCertstoreServer();
220 	_endthreadex( 0 );
221 	return( 0 );
222 	}
223 
testSessionHTTPCertstoreClientServer(void)224 int testSessionHTTPCertstoreClientServer( void )
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 
connectRTCS(const CRYPT_SESSION_TYPE sessionType,const BOOLEAN multipleCerts,const BOOLEAN localSession)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 */
308 		filenameFromTemplate( filenameBuffer, SERVER_PRIVKEY_FILE_TEMPLATE, 1 );
309 #ifdef UNICODE_STRINGS
310 		mbstowcs( wcBuffer, filenameBuffer, strlen( filenameBuffer ) + 1 );
311 		fileNamePtr = wcBuffer;
312 #endif /* UNICODE_STRINGS */
313 		status = getPrivateKey( &cryptPrivateKey, fileNamePtr,
314 								USER_PRIVKEY_LABEL, TEST_PRIVKEY_PASSWORD );
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,
328 								  DATABASE_KEYSET_TYPE, CERTSTORE_KEYSET_NAME,
329 								  CRYPT_KEYOPT_READONLY );
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,
370 								  DATABASE_KEYSET_TYPE, CERTSTORE_KEYSET_NAME,
371 								  CRYPT_KEYOPT_READONLY );
372 		if( cryptStatusOK( status ) )
373 			{
374 			status = cryptGetPublicKey( cryptKeyset, &cryptCert,
375 										CRYPT_KEYID_NAME,
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 			puts( "  (Has the testCertManagement() code been run?)." );
384 			return( FALSE );
385 			}
386 
387 		/* Create the RTCS request */
388 		if( !initRTCS( &cryptRTCSRequest, cryptCert, localSession ? \
389 							1 : RTCS_SERVER_NO, multipleCerts ) )
390 			return( FALSE );
391 		cryptDestroyCert( cryptCert );
392 
393 		/* Set up the server information and activate the session.  In
394 		   theory the RTCS request will contain all the information needed
395 		   for the session so there'd be nothing else to add before we
396 		   activate it, however many certs contain incorrect server URLs so
397 		   we set the server name manually if necessary, overriding the
398 		   value present in the RTCS request (via the certificate) */
399 		status = cryptSetAttribute( cryptSession, CRYPT_SESSINFO_REQUEST,
400 									cryptRTCSRequest );
401 		if( cryptStatusError( status ) )
402 			return( attrErrorExit( cryptSession, "cryptSetAttribute()",
403 								   status, __LINE__ ) );
404 		cryptDestroyCert( cryptRTCSRequest );
405 		if( localSession && !setLocalConnect( cryptSession, 80 ) )
406 			return( FALSE );
407 #ifdef RTCS_SERVER_NAME
408 		if( !localSession )
409 			{
410 			printf( "Setting RTCS server to %s.\n", RTCS_SERVER_NAME );
411 			cryptDeleteAttribute( cryptSession, CRYPT_SESSINFO_SERVER_NAME );
412 			status = cryptSetAttributeString( cryptSession,
413 								CRYPT_SESSINFO_SERVER_NAME, RTCS_SERVER_NAME,
414 								paramStrlen( RTCS_SERVER_NAME ) );
415 			if( cryptStatusError( status ) )
416 				return( attrErrorExit( cryptSession,
417 									   "cryptSetAttributeString()", status,
418 									   __LINE__ ) );
419 			}
420 #endif /* Kludges for incorrect/missing authorityInfoAccess values */
421 
422 		/* Wait for the server to finish initialising */
423 		if( localSession && waitMutex() == CRYPT_ERROR_TIMEOUT )
424 			{
425 			printf( "Timed out waiting for server to initialise, line %d.\n",
426 					__LINE__ );
427 			return( FALSE );
428 			}
429 		}
430 	status = cryptSetAttribute( cryptSession, CRYPT_SESSINFO_ACTIVE, TRUE );
431 	if( isServer )
432 		printConnectInfo( cryptSession );
433 	if( cryptStatusError( status ) )
434 		{
435 		printExtError( cryptSession, isServer ? \
436 					   "SVR: Attempt to activate RTCS server session" : \
437 					   "Attempt to activate RTCS client session", status,
438 					   __LINE__ );
439 		if( !isServer && isServerDown( cryptSession, status ) )
440 			{
441 			puts( "  (Server could be down, faking it and continuing...)\n" );
442 			cryptDestroySession( cryptSession );
443 			return( CRYPT_ERROR_FAILED );
444 			}
445 		cryptDestroySession( cryptSession );
446 		return( FALSE );
447 		}
448 
449 	/* Obtain the response information */
450 	if( !isServer )
451 		{
452 		CRYPT_CERTIFICATE cryptRTCSResponse;
453 
454 		status = cryptGetAttribute( cryptSession, CRYPT_SESSINFO_RESPONSE,
455 									&cryptRTCSResponse );
456 		if( cryptStatusError( status ) )
457 			{
458 			printf( "cryptGetAttribute() failed with error code %d, line "
459 					"%d.\n", status, __LINE__ );
460 			return( FALSE );
461 			}
462 		printCertInfo( cryptRTCSResponse );
463 		cryptDestroyCert( cryptRTCSResponse );
464 		}
465 
466 	/* Clean up */
467 	status = cryptDestroySession( cryptSession );
468 	if( cryptStatusError( status ) )
469 		{
470 		printf( "cryptDestroySession() failed with error code %d, line %d.\n",
471 				status, __LINE__ );
472 		return( FALSE );
473 		}
474 
475 	puts( isServer ? "SVR: RTCS server session succeeded.\n" : \
476 					 "RTCS client session succeeded.\n" );
477 	return( TRUE );
478 	}
479 
connectRTCSDirect(void)480 static int connectRTCSDirect( void )
481 	{
482 	CRYPT_CERTIFICATE cryptCert;
483 	CRYPT_SESSION cryptSession;
484 	int status;
485 
486 	printf( "Testing direct RTCS query...\n" );
487 
488 	/* Get the EE certificate */
489 	status = importCertFromTemplate( &cryptCert, RTCS_FILE_TEMPLATE,
490 									 RTCS_SERVER_NO );
491 	if( cryptStatusError( status ) )
492 		{
493 		printf( "EE cryptImportCert() failed with error code %d, line %d.\n",
494 				status, __LINE__ );
495 		return( FALSE );
496 		}
497 
498 	/* Create the RTCS session and add the server URL */
499 	status = cryptCreateSession( &cryptSession, CRYPT_UNUSED,
500 								 CRYPT_SESSION_RTCS );
501 	if( status == CRYPT_ERROR_PARAM3 )	/* RTCS session access not available */
502 		return( CRYPT_ERROR_NOTAVAIL );
503 #ifdef RTCS_SERVER_NAME
504 	status = cryptSetAttributeString( cryptSession,
505 								CRYPT_SESSINFO_SERVER_NAME, RTCS_SERVER_NAME,
506 								paramStrlen( RTCS_SERVER_NAME ) );
507 	if( cryptStatusError( status ) )
508 		return( attrErrorExit( cryptSession, "cryptSetAttributeString()",
509 							   status, __LINE__ ) );
510 #endif /* Kludges for incorrect/missing authorityInfoAccess values */
511 
512 	/* Check the certificate directly against the server */
513 	status = cryptCheckCert( cryptCert, cryptSession );
514 	printf( "Certificate status check returned %d.\n", status );
515 
516 	/* Clean up */
517 	cryptDestroyCert( cryptCert );
518 	cryptDestroySession( cryptSession );
519 
520 	puts( "RTCS direct query succeeded.\n" );
521 	return( TRUE );
522 	}
523 
testSessionRTCS(void)524 int testSessionRTCS( void )
525 	{
526 	if( !connectRTCS( CRYPT_SESSION_RTCS, FALSE, FALSE ) )
527 		return( FALSE );
528 	if( !connectRTCSDirect() )
529 		return( FALSE );
530 #if RTCS_SERVER_NO == 1
531 	return( connectRTCS( CRYPT_SESSION_RTCS, TRUE, FALSE ) );
532 #else
533 	return( TRUE );
534 #endif /* Server that has a revoked certificate */
535 	}
testSessionRTCSServer(void)536 int testSessionRTCSServer( void )
537 	{
538 	int status;
539 
540 	createMutex();
541 	acquireMutex();
542 	status = connectRTCS( CRYPT_SESSION_RTCS_SERVER, FALSE, FALSE );
543 	destroyMutex();
544 
545 	return( status );
546 	}
547 
548 /* Perform a client/server loopback test */
549 
550 #ifdef WINDOWS_THREADS
551 
rtcsServerThread(void * dummy)552 unsigned __stdcall rtcsServerThread( void *dummy )
553 	{
554 	acquireMutex();
555 	connectRTCS( CRYPT_SESSION_RTCS_SERVER, FALSE, TRUE );
556 	_endthreadex( 0 );
557 	return( 0 );
558 	}
559 
testSessionRTCSClientServer(void)560 int testSessionRTCSClientServer( void )
561 	{
562 	HANDLE hThread;
563 	unsigned threadID;
564 	int status;
565 
566 	/* Start the server and wait for it to initialise */
567 	createMutex();
568 	hThread = ( HANDLE ) _beginthreadex( NULL, 0, rtcsServerThread,
569 										 NULL, 0, &threadID );
570 	Sleep( 2000 );
571 
572 	/* Connect to the local server */
573 	status = connectRTCS( CRYPT_SESSION_RTCS, FALSE, TRUE );
574 	waitForThread( hThread );
575 	destroyMutex();
576 	return( status );
577 	}
578 #endif /* WINDOWS_THREADS */
579 
580 /****************************************************************************
581 *																			*
582 *								OCSP Routines Test							*
583 *																			*
584 ****************************************************************************/
585 
586 /* There are various test OCSP servers running, the following remapping
587    allows us to switch between them.  Implementation peculiarities:
588 
589 	#1 - cryptlib:
590 			None
591 	#2 - iD2 aka SmartTrust
592 			AuthorityInfoAccess doesn't match the real server URL, requires
593 			the SmartTrust server name below to override the AIA value.
594 			Currently not active.
595 	#3 - Identrus aka Xetex:
596 			AuthorityInfoAccess doesn't match the real server URL, requires
597 			the Xetex server name below to override the AIA value.  Currently
598 			not active.
599 	#4 - Thawte aka Valicert
600 			No AuthorityInfoAccess, requires the Valicert server name below
601 			to provide a server.  Since all Thawte CA certs are invalid (no
602 			keyUsage, meaning they're non-CA certs) cryptlib will reject them
603 			for OCSPv1 queries.
604 	#5 - Verisign
605 			No AuthorityInfoAccess, requires the Verisign server name below
606 			to provide a server.
607 	#6 - Diginotar
608 			Have an invalid CA certificate, and (apparently) a broken OCSP
609 			implementation that gets the IDs wrong (this is par for the
610 			course for this particular CA).
611 	#7 - Windows Server 2008
612 			Returns a permission-denied error with the default server
613 			configuration.  This is because Windows Server by default doesn't
614 			allow nonces, and responds to any request containing a nonce
615 			with a permission-denied error.  Enabling nonces via Revocation
616 			Configurations | Action | Edit Properties | Allow Nonce requests
617 			corrects this */
618 
619 #define OCSP_SERVER_NO		5
620 #if OCSP_SERVER_NO == 2
621   #define OCSP_SERVER_NAME	TEXT( "http://ocsp.smarttrust.com:82/ocsp" )
622 #elif OCSP_SERVER_NO == 3
623   #define OCSP_SERVER_NAME	TEXT( "http://ocsp.xetex.com:8080/servlet/ocsp" )
624 #elif OCSP_SERVER_NO == 4
625   #define OCSP_SERVER_NAME	TEXT( "http://ocsp2.valicert.net" )
626 #elif OCSP_SERVER_NO == 5
627   #define OCSP_SERVER_NAME	TEXT( "http://ocsp.verisign.com/ocsp/status" )
628 #elif OCSP_SERVER_NO == 7
629 	#define OCSP_SERVER_NAME	TEXT( "http://142.176.86.157/ocsp" )
630 #endif /* OCSP server name kludge */
631 
632 /* Perform an OCSP test */
633 
connectOCSP(const CRYPT_SESSION_TYPE sessionType,const BOOLEAN revokedCert,const BOOLEAN multipleCerts,const BOOLEAN localSession)634 static int connectOCSP( const CRYPT_SESSION_TYPE sessionType,
635 						const BOOLEAN revokedCert,
636 						const BOOLEAN multipleCerts,
637 						const BOOLEAN localSession )
638 	{
639 	CRYPT_SESSION cryptSession;
640 	CRYPT_CERTIFICATE cryptOCSPRequest, cryptCert1, cryptCert2;
641 	char filenameBuffer[ FILENAME_BUFFER_SIZE ];
642 #ifdef UNICODE_STRINGS
643 	wchar_t wcBuffer[ FILENAME_BUFFER_SIZE ];
644 #endif /* UNICODE_STRINGS */
645 	void *fileNamePtr = filenameBuffer;
646 #if OCSP_SERVER_NO == 7
647 	int complianceValue;
648 #endif /* OCSP servers that return broken resposnes */
649 	const BOOLEAN isServer = ( sessionType == CRYPT_SESSION_OCSP_SERVER ) ? \
650 							   TRUE : FALSE;
651 	int status;
652 
653 	printf( "%sTesting %sOCSP session...\n", isServer ? "SVR: " : "",
654 			localSession ? "local " : "" );
655 
656 	/* If we're the client, wait for the server to finish initialising */
657 	if( localSession && !isServer && waitMutex() == CRYPT_ERROR_TIMEOUT )
658 		{
659 		printf( "Timed out waiting for server to initialise, line %d.\n",
660 				__LINE__ );
661 		return( FALSE );
662 		}
663 
664 	/* Create the OCSP session */
665 	status = cryptCreateSession( &cryptSession, CRYPT_UNUSED, sessionType );
666 	if( status == CRYPT_ERROR_PARAM3 )	/* OCSP session access not available */
667 		return( CRYPT_ERROR_NOTAVAIL );
668 	if( cryptStatusError( status ) )
669 		{
670 		printf( "cryptCreateSession() failed with error code %d, line %d.\n",
671 				status, __LINE__ );
672 		return( FALSE );
673 		}
674 	if( isServer )
675 		{
676 		CRYPT_CONTEXT cryptPrivateKey;
677 		CRYPT_KEYSET cryptCertStore;
678 
679 		if( !setLocalConnect( cryptSession, 80 ) )
680 			return( FALSE );
681 
682 		/* Add the responder private key */
683 		filenameFromTemplate( filenameBuffer, SERVER_PRIVKEY_FILE_TEMPLATE, 1 );
684 #ifdef UNICODE_STRINGS
685 		mbstowcs( wcBuffer, filenameBuffer, strlen( filenameBuffer ) + 1 );
686 		fileNamePtr = wcBuffer;
687 #endif /* UNICODE_STRINGS */
688 		status = getPrivateKey( &cryptPrivateKey, fileNamePtr,
689 								USER_PRIVKEY_LABEL, TEST_PRIVKEY_PASSWORD );
690 		if( cryptStatusOK( status ) )
691 			{
692 			status = cryptSetAttribute( cryptSession,
693 							CRYPT_SESSINFO_PRIVATEKEY, cryptPrivateKey );
694 			cryptDestroyContext( cryptPrivateKey );
695 			}
696 		if( cryptStatusError( status ) )
697 			return( attrErrorExit( cryptSession, "SVR: cryptSetAttribute()",
698 								   status, __LINE__ ) );
699 
700 		/* Add the certificate store that we'll be using to provide
701 		   revocation information */
702 		status = cryptKeysetOpen( &cryptCertStore, CRYPT_UNUSED,
703 								  DATABASE_KEYSET_TYPE, CERTSTORE_KEYSET_NAME,
704 								  CRYPT_KEYOPT_READONLY );
705 		if( status == CRYPT_ERROR_PARAM3 )
706 			{
707 			/* This type of keyset access isn't available, return a special
708 			   error code to indicate that the test wasn't performed, but
709 			   that this isn't a reason to abort processing */
710 			puts( "SVR: No certificate store available, aborting OCSP "
711 				  "responder test.\n" );
712 			cryptDestroySession( cryptSession );
713 			return( CRYPT_ERROR_NOTAVAIL );
714 			}
715 		if( status == CRYPT_ERROR_OPEN )
716 			{
717 			/* This is the first of the loopback tests that requires the
718 			   presence of a certificate store (created by previous tests),
719 			   if we can't open it then we report the issue in a situation-
720 			   specific manner */
721 			puts( "SVR: Can't open certificate store, have the earlier "
722 				  "tests that create this\n     been run?\n" );
723 			cryptDestroySession( cryptSession );
724 			return( status );
725 			}
726 		if( cryptStatusOK( status ) )
727 			{
728 			status = cryptSetAttribute( cryptSession,
729 							CRYPT_SESSINFO_KEYSET, cryptCertStore );
730 			cryptKeysetClose( cryptCertStore );
731 			}
732 		if( cryptStatusError( status ) )
733 			return( attrErrorExit( cryptSession, "SVR: cryptSetAttribute()",
734 								   status, __LINE__ ) );
735 
736 		/* Tell the client that we're ready to go */
737 		if( localSession )
738 			releaseMutex();
739 		}
740 	else
741 		{
742 		/* Create the OCSP request */
743 		if( !initOCSP( &cryptOCSPRequest, &cryptCert1, &cryptCert2,
744 					   localSession ? 1 : OCSP_SERVER_NO, FALSE,
745 					   revokedCert, multipleCerts,
746 					   CRYPT_SIGNATURELEVEL_NONE, CRYPT_UNUSED ) )
747 			return( FALSE );
748 
749 		/* Set up the server information and activate the session.  In
750 		   theory the OCSP request will contain all the information needed
751 		   for the session so there'd be nothing else to add before we
752 		   activate it, however many certs contain incorrect server URLs so
753 		   we set the server name manually if necessary, overriding the
754 		   value present in the OCSP request (via the certificate) */
755 		status = cryptSetAttribute( cryptSession, CRYPT_SESSINFO_REQUEST,
756 									cryptOCSPRequest );
757 		if( cryptStatusError( status ) )
758 			return( attrErrorExit( cryptSession, "cryptSetAttribute()",
759 								   status, __LINE__ ) );
760 		cryptDestroyCert( cryptOCSPRequest );
761 		if( localSession && !setLocalConnect( cryptSession, 80 ) )
762 			return( FALSE );
763 #ifdef OCSP_SERVER_NAME
764 		if( !localSession )
765 			{
766 			printf( "Setting OCSP server to %s.\n", OCSP_SERVER_NAME );
767 			cryptDeleteAttribute( cryptSession, CRYPT_SESSINFO_SERVER_NAME );
768 			status = cryptSetAttributeString( cryptSession,
769 								CRYPT_SESSINFO_SERVER_NAME, OCSP_SERVER_NAME,
770 								paramStrlen( OCSP_SERVER_NAME ) );
771 			if( cryptStatusError( status ) )
772 				{
773 				return( attrErrorExit( cryptSession,
774 									   "cryptSetAttributeString()", status,
775 									   __LINE__ ) );
776 				}
777 			}
778 #endif /* Kludges for incorrect/missing authorityInfoAccess values */
779 		if( OCSP_SERVER_NO == 1 || localSession )
780 			{
781 			/* The cryptlib server doesn't handle the weird v1 certIDs */
782 			status = cryptSetAttribute( cryptSession, CRYPT_SESSINFO_VERSION,
783 										2 );
784 			if( cryptStatusError( status ) )
785 				{
786 				return( attrErrorExit( cryptSession, "cryptSetAttribute()",
787 									   status, __LINE__ ) );
788 				}
789 			}
790 #if OCSP_SERVER_NO == 7
791 		/* Some OCSP server's responses are broken so we have to turn down
792 		   the compliance level to allow them to be processed */
793 		cryptGetAttribute( CRYPT_UNUSED, CRYPT_OPTION_CERT_COMPLIANCELEVEL,
794 						   &complianceValue );
795 		cryptSetAttribute( CRYPT_UNUSED, CRYPT_OPTION_CERT_COMPLIANCELEVEL,
796 						   CRYPT_COMPLIANCELEVEL_OBLIVIOUS );
797 #endif /* OCSP servers that return broken resposnes */
798 
799 		/* Wait for the server to finish initialising */
800 		if( localSession && waitMutex() == CRYPT_ERROR_TIMEOUT )
801 			{
802 			printf( "Timed out waiting for server to initialise, line %d.\n",
803 					__LINE__ );
804 			return( FALSE );
805 			}
806 		}
807 	status = cryptSetAttribute( cryptSession, CRYPT_SESSINFO_ACTIVE, TRUE );
808 #if OCSP_SERVER_NO == 7
809 	if( !isServer )
810 		{
811 		/* Restore normal certificate processing */
812 		cryptSetAttribute( CRYPT_UNUSED, CRYPT_OPTION_CERT_COMPLIANCELEVEL,
813 						   complianceValue );
814 		}
815 #endif /* OCSP servers that return broken resposnes */
816 	if( isServer )
817 		printConnectInfo( cryptSession );
818 	if( cryptStatusError( status ) )
819 		{
820 		printExtError( cryptSession, isServer ? \
821 					   "SVR: Attempt to activate OCSP server session" : \
822 					   "Attempt to activate OCSP client session", status,
823 					   __LINE__ );
824 #if OCSP_SERVER_NO == 5
825 		if( status == CRYPT_ERROR_SIGNATURE )
826 			{
827 			char errorMessage[ 512 ];
828 			int errorMessageLength;
829 
830 			status = cryptGetAttributeString( cryptSession,
831 											  CRYPT_ATTRIBUTE_ERRORMESSAGE,
832 											  errorMessage, &errorMessageLength );
833 			if( cryptStatusOK( status ) && errorMessageLength >= 29 && \
834 				!memcmp( errorMessage, "OCSP response doesn't contain", 29 ) )
835 				{
836 				cryptDestroyCert( cryptCert1 );
837 				if( cryptCert2 != CRYPT_UNUSED )
838 					cryptDestroyCert( cryptCert2 );
839 				cryptDestroySession( cryptSession );
840 				puts( "  (Verisign's OCSP responder sends broken responses, "
841 					  "continuing...)\n" );
842 				return( CRYPT_ERROR_FAILED );
843 				}
844 			}
845 #endif /* Verisign's broken OCSP responder */
846 		if( !isServer && isServerDown( cryptSession, status ) )
847 			{
848 			puts( "  (Server could be down, faking it and continuing...)\n" );
849 			cryptDestroyCert( cryptCert1 );
850 			if( cryptCert2 != CRYPT_UNUSED )
851 				cryptDestroyCert( cryptCert2 );
852 			cryptDestroySession( cryptSession );
853 			return( CRYPT_ERROR_FAILED );
854 			}
855 		cryptDestroySession( cryptSession );
856 		return( FALSE );
857 		}
858 
859 	/* Obtain the response information */
860 	if( !isServer )
861 		{
862 		CRYPT_CERTIFICATE cryptOCSPResponse;
863 
864 		/* Display the status information in the response */
865 		status = cryptGetAttribute( cryptSession, CRYPT_SESSINFO_RESPONSE,
866 									&cryptOCSPResponse );
867 		if( cryptStatusError( status ) )
868 			{
869 			printf( "cryptGetAttribute() failed with error code %d, line "
870 					"%d.\n", status, __LINE__ );
871 			return( FALSE );
872 			}
873 		printCertInfo( cryptOCSPResponse );
874 
875 		/* Check each certificate against the response.  This is somewhat
876 		   redundant since the status has already been displayed by the code
877 		   above, but it tests the check-against-response functionality */
878 		status = cryptCheckCert( cryptCert1, cryptOCSPResponse );
879 		printf( "Check of certificate status against OCSP response reports "
880 				"status %d.\n", status );
881 		if( cryptCert2 != CRYPT_UNUSED )
882 			{
883 			status = cryptCheckCert( cryptCert2, cryptOCSPResponse );
884 			printf( "Check of second certificate status against OCSP "
885 					"response reports status %d.\n", status );
886 			}
887 
888 		cryptDestroyCert( cryptOCSPResponse );
889 		cryptDestroyCert( cryptCert1 );
890 		if( cryptCert2 != CRYPT_UNUSED )
891 			cryptDestroyCert( cryptCert2 );
892 		}
893 
894 	/* There are so many weird ways to delegate trust and signing authority
895 	   mentioned in the OCSP RFC without any indication of which one
896 	   implementors will follow that we can't really perform any sort of
897 	   automated check since every responder seems to interpret this
898 	   differently, and many require manual installation of responder certs
899 	   in order to function */
900 #if 0
901 	status = cryptCheckCert( cryptOCSPResponse , CRYPT_UNUSED );
902 	if( cryptStatusError( status ) )
903 		return( attrErrorExit( cryptOCSPResponse , "cryptCheckCert()",
904 							   status, __LINE__ ) );
905 #endif /* 0 */
906 
907 	/* Clean up */
908 	status = cryptDestroySession( cryptSession );
909 	if( cryptStatusError( status ) )
910 		{
911 		printf( "cryptDestroySession() failed with error code %d, line %d.\n",
912 				status, __LINE__ );
913 		return( FALSE );
914 		}
915 
916 	puts( isServer ? "SVR: OCSP server session succeeded.\n" : \
917 					 "OCSP client session succeeded.\n" );
918 	return( TRUE );
919 	}
920 
connectOCSPDirect(void)921 static int connectOCSPDirect( void )
922 	{
923 	CRYPT_CERTIFICATE cryptCert;
924 	CRYPT_SESSION cryptSession;
925 	int status;
926 
927 	printf( "Testing direct OCSP query...\n" );
928 
929 	/* Get the EE certificate */
930 	status = importCertFromTemplate( &cryptCert, OCSP_EEOK_FILE_TEMPLATE,
931 									 OCSP_SERVER_NO );
932 	if( cryptStatusError( status ) )
933 		{
934 		printf( "EE cryptImportCert() failed with error code %d, line %d.\n",
935 				status, __LINE__ );
936 		return( FALSE );
937 		}
938 
939 	/* Create the OCSP session and add the server URL */
940 	status = cryptCreateSession( &cryptSession, CRYPT_UNUSED,
941 								 CRYPT_SESSION_OCSP );
942 	if( status == CRYPT_ERROR_PARAM3 )	/* OCSP session access not available */
943 		return( CRYPT_ERROR_NOTAVAIL );
944 #ifdef OCSP_SERVER_NAME
945 	status = cryptSetAttributeString( cryptSession,
946 								CRYPT_SESSINFO_SERVER_NAME, OCSP_SERVER_NAME,
947 								paramStrlen( OCSP_SERVER_NAME ) );
948 	if( cryptStatusError( status ) )
949 		return( attrErrorExit( cryptSession, "cryptSetAttributeString()",
950 							   status, __LINE__ ) );
951 #endif /* Kludges for incorrect/missing authorityInfoAccess values */
952 
953 	/* Check the certificate directly against the server.  This check
954 	   quantises the result into a basic pass/fail that doesn't provide as
955 	   much detail as the low-level OCSP check, so it's not unusual to get
956 	   CRYPT_ERROR_INVALID whent he low-level check returns
957 	   CRYPT_OCSPSTATUS_UNKNOWN */
958 	status = cryptCheckCert( cryptCert, cryptSession );
959 	printf( "Certificate status check returned %d.\n", status );
960 
961 	/* Clean up */
962 	cryptDestroyCert( cryptCert );
963 	cryptDestroySession( cryptSession );
964 
965 	puts( "OCSP direct query succeeded.\n" );
966 	return( TRUE );
967 	}
968 
testSessionOCSP(void)969 int testSessionOCSP( void )
970 	{
971 	if( !connectOCSP( CRYPT_SESSION_OCSP, FALSE, FALSE, FALSE ) )
972 		return( FALSE );
973 	if( !connectOCSPDirect() )
974 		return( FALSE );
975 #if OCSP_SERVER_NO == 1
976 	if( !( connectOCSP( CRYPT_SESSION_OCSP, TRUE, FALSE, FALSE ) ) )
977 		return( FALSE );
978 	return( connectOCSP( CRYPT_SESSION_OCSP, FALSE, TRUE, FALSE ) );
979 #else
980 	return( TRUE );
981 #endif /* Server that has a revoked certificate */
982 	}
testSessionOCSPServer(void)983 int testSessionOCSPServer( void )
984 	{
985 	return( connectOCSP( CRYPT_SESSION_OCSP_SERVER, FALSE, FALSE, FALSE ) );
986 	}
987 
988 /* Perform a client/server loopback test */
989 
990 #ifdef WINDOWS_THREADS
991 
ocspServerThread(void * dummy)992 unsigned __stdcall ocspServerThread( void *dummy )
993 	{
994 	acquireMutex();
995 	connectOCSP( CRYPT_SESSION_OCSP_SERVER, FALSE, FALSE, TRUE );
996 	_endthreadex( 0 );
997 	return( 0 );
998 	}
999 
testSessionOCSPClientServer(void)1000 int testSessionOCSPClientServer( void )
1001 	{
1002 	HANDLE hThread;
1003 	unsigned threadID;
1004 	int status;
1005 
1006 	/* Start the server and wait for it to initialise */
1007 	createMutex();
1008 	hThread = ( HANDLE ) _beginthreadex( NULL, 0, ocspServerThread,
1009 										 NULL, 0, &threadID );
1010 	Sleep( 1000 );
1011 
1012 	/* Connect to the local server */
1013 	status = connectOCSP( CRYPT_SESSION_OCSP, FALSE, FALSE, TRUE );
1014 	waitForThread( hThread );
1015 	destroyMutex();
1016 	return( status );
1017 	}
1018 
testSessionOCSPMulticertClientServer(void)1019 int testSessionOCSPMulticertClientServer( void )
1020 	{
1021 	HANDLE hThread;
1022 	unsigned threadID;
1023 	int status;
1024 
1025 	/* Start the server and wait for it to initialise */
1026 	createMutex();
1027 	hThread = ( HANDLE ) _beginthreadex( NULL, 0, ocspServerThread,
1028 										 NULL, 0, &threadID );
1029 	Sleep( 1000 );
1030 
1031 	/* Connect to the local server */
1032 	status = connectOCSP( CRYPT_SESSION_OCSP, FALSE, TRUE, TRUE );
1033 	waitForThread( hThread );
1034 	destroyMutex();
1035 	return( status );
1036 	}
1037 #endif /* WINDOWS_THREADS */
1038 
1039 /****************************************************************************
1040 *																			*
1041 *								TSP Routines Test							*
1042 *																			*
1043 ****************************************************************************/
1044 
1045 /* There are various test TSP servers running, the following remapping allows
1046    us to switch between them in the hope of finding at least one which is
1047    actually working.  Implementation peculiarities:
1048 
1049 	#1 - cryptlib:
1050 			None.
1051 	#2 - Peter Sylvester
1052 			Requires Host: header even for HTTP 1.0.
1053 	#3 - Timeproof
1054 			None (currently not active).
1055 	#4 - Korea Mobile Payment Service
1056 			Currently not active.
1057 	#5 - IAIK Graz
1058 			Never been seen active.
1059 	#6 - Fst s.r.l.
1060 			Returns garbled TCP-socket-protocol header.
1061 	#7 - Datum
1062 			Almost never active
1063 	#8 - Chinese University of Hong Kong
1064 			None, info at http://www.e-timestamping.com/status.html.
1065 	#9 - SeMarket
1066 			None.
1067 	#10 - Entrust
1068 			None.
1069 	#11 - nCipher
1070 			Very slow TSP, requires extended read timeout to get response.
1071 	#12 - Comodo
1072 			None.
1073 	#13 - Verisign
1074 			This "TSA" doesn't support TSP but uses an AuthentiCode-specific
1075 			mechanism documented at
1076 			http://msdn.microsoft.com/en-us/library/windows/desktop/bb931395%28v=vs.85%29.aspx.
1077 			Submitting a TSP request returns the text message "error
1078 			handling request, status = 0x9300"
1079 	#14 - SecureSoft
1080 			None (but uses an invalid policy OID '1 2' in the response).
1081 	#15 - OpenTSA
1082 			Currently not active, info at http://opentsa.org/#service
1083 
1084    Note that this only tests the low-level raw TSP mechanism, timestamps are
1085    usually used in conjunction with signed (enveloped) data, for which see
1086    testSessionEnvTSP() */
1087 
1088 #define TSP_SERVER1_NAME	TEXT( "localhost" )
1089 #define TSP_SERVER2_NAME	TEXT( "http://timestamping.edelweb.fr/service/tsp" )
1090 #define TSP_SERVER3_NAME	TEXT( "tcp://test.timeproof.de" )
1091 #define TSP_SERVER4_NAME	TEXT( "tcp://203.238.37.132:3318" )
1092 #define TSP_SERVER5_NAME	TEXT( "tcp://neurath.iaik.at" )
1093 #define TSP_SERVER6_NAME	TEXT( "tcp://ricerca.fst.it" )
1094 #define TSP_SERVER7_NAME	TEXT( "tcp://tssdemo2.datum.com" )
1095 #define TSP_SERVER8_NAME	TEXT( "tcp://ts2.itsc.cuhk.edu.hk:3318" )
1096 #define TSP_SERVER9_NAME	TEXT( "tcp://80.81.104.150" )
1097 #define TSP_SERVER10_NAME	TEXT( "http://vsinterop.entrust.com:7001/verificationserver/rfc3161timestamp" )
1098 #define TSP_SERVER11_NAME	TEXT( "tcp://dse200.ncipher.com" )
1099 #define TSP_SERVER12_NAME	TEXT( "http://timestamp.comodoca.com/rfc3161" )
1100 #define TSP_SERVER13_NAME	TEXT( "http://timestamp.verisign.com/scripts/timstamp.dll" )
1101 #define TSP_SERVER14_NAME	TEXT( "http://ca.signfiles.com/TSAServer.aspx" )
1102 #define TSP_SERVER15_NAME	TEXT( "http://ns.szikszi.hu:8080/tsa" )
1103 
1104 #define TSP_SERVER_NAME		TSP_SERVER2_NAME
1105 #define TSP_SERVER_NO		2	/* Only used to identify slow-timeout server #11 */
1106 
1107 /* Perform a timestamping test */
1108 
testTSP(const CRYPT_SESSION cryptSession,const BOOLEAN isServer,const BOOLEAN isRecycledConnection,const BOOLEAN useAltHash,const BOOLEAN localSession)1109 static int testTSP( const CRYPT_SESSION cryptSession,
1110 					const BOOLEAN isServer,
1111 					const BOOLEAN isRecycledConnection,
1112 					const BOOLEAN useAltHash,
1113 					const BOOLEAN localSession )
1114 	{
1115 	int status;
1116 
1117 	/* If we're the client, wait for the server to finish initialising */
1118 	if( localSession && !isServer && waitMutex() == CRYPT_ERROR_TIMEOUT )
1119 		{
1120 		printf( "Timed out waiting for server to initialise, line %d.\n",
1121 				__LINE__ );
1122 		return( FALSE );
1123 		}
1124 
1125 	/* If we're the client, create a message imprint to timestamp */
1126 	if( !isServer )
1127 		{
1128 		CRYPT_CONTEXT hashContext;
1129 
1130 		/* Create the hash value to add to the TSP request */
1131 		status = cryptCreateContext( &hashContext, CRYPT_UNUSED,
1132 									 useAltHash ? CRYPT_ALGO_SHA256 : \
1133 												  CRYPT_ALGO_SHA1 );
1134 		if( cryptStatusError( status ) )
1135 			return( FALSE );
1136 		cryptEncrypt( hashContext, "12345678", 8 );
1137 		cryptEncrypt( hashContext, "", 0 );
1138 		if( isRecycledConnection )
1139 			{
1140 			/* If we're moving further data over an existing connection,
1141 			   delete the message imprint from the previous run */
1142 			status = cryptDeleteAttribute( cryptSession,
1143 										   CRYPT_SESSINFO_TSP_MSGIMPRINT );
1144 			if( cryptStatusError( status ) )
1145 				{
1146 				printf( "cryptDeleteAttribute() failed with error code %d, "
1147 						"line %d.\n", status, __LINE__ );
1148 				return( FALSE );
1149 				}
1150 			}
1151 		status = cryptSetAttribute( cryptSession,
1152 									CRYPT_SESSINFO_TSP_MSGIMPRINT,
1153 									hashContext );
1154 		if( cryptStatusError( status ) )
1155 			{
1156 			printf( "cryptSetAttribute() failed with error code %d, line "
1157 					"%d.\n", status, __LINE__ );
1158 			return( FALSE );
1159 			}
1160 		cryptDestroyContext( hashContext );
1161 
1162 		/* If it's a local session, wait for the server to finish
1163 		   initialising */
1164 		if( localSession && waitMutex() == CRYPT_ERROR_TIMEOUT )
1165 			{
1166 			printf( "Timed out waiting for server to initialise, line %d.\n",
1167 					__LINE__ );
1168 			return( FALSE );
1169 			}
1170 		}
1171 	else
1172 		{
1173 		/* We're the server, if this is the first connect tell the client
1174 		   that we're ready to go */
1175 		if( localSession && !isRecycledConnection )
1176 			releaseMutex();
1177 		}
1178 
1179 	/* Activate the session and timestamp the message */
1180 #if TSP_SERVER_NO == 11
1181 	cryptSetAttribute( cryptSession, CRYPT_OPTION_NET_READTIMEOUT, 30 );
1182 #endif /* Very slow TSP */
1183 	status = cryptSetAttribute( cryptSession, CRYPT_SESSINFO_ACTIVE, TRUE );
1184 	if( isServer )
1185 		printConnectInfo( cryptSession );
1186 	if( cryptStatusError( status ) )
1187 		{
1188 		printExtError( cryptSession, isServer ? \
1189 					   "SVR: Attempt to activate TSP server session" : \
1190 					   "Attempt to activate TSP client session", status,
1191 					   __LINE__ );
1192 		if( !isServer && isServerDown( cryptSession, status ) )
1193 			{
1194 			puts( "  (Server could be down, faking it and continuing...)\n" );
1195 			cryptDestroySession( cryptSession );
1196 			return( CRYPT_ERROR_FAILED );
1197 			}
1198 		cryptDestroySession( cryptSession );
1199 		return( FALSE );
1200 		}
1201 
1202 	/* There's not much more we can do in the client at this point since the
1203 	   TSP data is only used internally by cryptlib, OTOH if we get to here
1204 	   then we've received a valid response from the TSA so all is OK */
1205 	if( !isServer )
1206 		{
1207 		CRYPT_ENVELOPE cryptEnvelope;
1208 		BYTE buffer[ BUFFER_SIZE ];
1209 		int bytesCopied;
1210 
1211 		status = cryptGetAttribute( cryptSession, CRYPT_SESSINFO_RESPONSE,
1212 									&cryptEnvelope );
1213 		if( cryptStatusError( status ) )
1214 			{
1215 			printExtError( cryptSession, "Attempt to process returned "
1216 						   "timestamp", status, __LINE__ );
1217 			return( FALSE );
1218 			}
1219 		status = cryptPopData( cryptEnvelope, buffer, BUFFER_SIZE,
1220 							   &bytesCopied );
1221 		if( cryptStatusError( status ) )
1222 			{
1223 			printf( "cryptPopData() failed with error code %d, line %d.\n",
1224 					status, __LINE__ );
1225 			return( FALSE );
1226 			}
1227 		printf( "Timestamp data size = %d bytes.\n", bytesCopied );
1228 		debugDump( "tstinfo", buffer, bytesCopied );
1229 		cryptDestroyEnvelope( cryptEnvelope );
1230 		}
1231 
1232 	return( TRUE );
1233 	}
1234 
connectTSP(const CRYPT_SESSION_TYPE sessionType,const CRYPT_HANDLE externalCryptContext,const BOOLEAN persistentConnection,const BOOLEAN localSession)1235 static int connectTSP( const CRYPT_SESSION_TYPE sessionType,
1236 					   const CRYPT_HANDLE externalCryptContext,
1237 					   const BOOLEAN persistentConnection,
1238 					   const BOOLEAN localSession )
1239 	{
1240 	CRYPT_SESSION cryptSession;
1241 	const BOOLEAN isServer = ( sessionType == CRYPT_SESSION_TSP_SERVER ) ? \
1242 							   TRUE : FALSE;
1243 	const BOOLEAN useAltHash = ( !isServer && 0 ) ? TRUE : FALSE;
1244 	int status;
1245 
1246 	printf( "%sTesting %sTSP session...\n", isServer ? "SVR: " : "",
1247 			localSession ? "local " : "" );
1248 
1249 	/* Acquire the init mutex if we're the server */
1250 	if( localSession && isServer && waitMutex() == CRYPT_ERROR_TIMEOUT )
1251 		{
1252 		printf( "Timed out waiting for server to initialise, line %d.\n",
1253 				__LINE__ );
1254 		return( FALSE );
1255 		}
1256 
1257 	/* Create the TSP session */
1258 	status = cryptCreateSession( &cryptSession, CRYPT_UNUSED, sessionType );
1259 	if( status == CRYPT_ERROR_PARAM3 )	/* TSP session access not available */
1260 		return( CRYPT_ERROR_NOTAVAIL );
1261 	if( cryptStatusError( status ) )
1262 		{
1263 		printf( "%scryptCreateSession() failed with error code %d, line "
1264 				"%d.\n", isServer ? "SVR: " : "", status, __LINE__ );
1265 		return( FALSE );
1266 		}
1267 
1268 	/* Set up the server information and activate the session.  Since this
1269 	   test explicitly tests the ability to handle persistent connections,
1270 	   we don't use the general-purpose request/response server wrapper,
1271 	   which only uses persistent connections opportunistically */
1272 	if( isServer )
1273 		{
1274 		CRYPT_CONTEXT privateKey = externalCryptContext;
1275 
1276 		if( !setLocalConnect( cryptSession, 318 ) )
1277 			return( FALSE );
1278 		if( externalCryptContext == CRYPT_UNUSED )
1279 			status = getPrivateKey( &privateKey, TSA_PRIVKEY_FILE,
1280 									USER_PRIVKEY_LABEL,
1281 									TEST_PRIVKEY_PASSWORD );
1282 		if( cryptStatusOK( status ) )
1283 			{
1284 			status = cryptSetAttribute( cryptSession,
1285 							CRYPT_SESSINFO_PRIVATEKEY, privateKey );
1286 			if( externalCryptContext == CRYPT_UNUSED )
1287 				cryptDestroyContext( privateKey );
1288 			}
1289 		}
1290 	else
1291 		{
1292 		if( localSession )
1293 			{
1294 			if( !setLocalConnect( cryptSession, 318 ) )
1295 				return( FALSE );
1296 			}
1297 		else
1298 			{
1299 			status = cryptSetAttributeString( cryptSession,
1300 							CRYPT_SESSINFO_SERVER_NAME, TSP_SERVER_NAME,
1301 							paramStrlen( TSP_SERVER_NAME ) );
1302 			}
1303 		}
1304 	if( cryptStatusError( status ) )
1305 		{
1306 		printf( "cryptSetAttribute/cryptSetAttributeString() failed with "
1307 				"error code %d, line %d.\n", status, __LINE__ );
1308 		return( FALSE );
1309 		}
1310 	status = testTSP( cryptSession, isServer, FALSE, useAltHash, localSession );
1311 	if( status <= 0 )
1312 		return( status );
1313 
1314 	/* Check whether the session connection is still open */
1315 	if( persistentConnection )
1316 		{
1317 		int connectionActive;
1318 
1319 		status = cryptGetAttribute( cryptSession, CRYPT_SESSINFO_CONNECTIONACTIVE,
1320 									&connectionActive );
1321 		if( cryptStatusError( status ) || !connectionActive )
1322 			{
1323 			printExtError( cryptSession, isServer ? \
1324 						   "SVR: Persistent connection has been closed, "
1325 							"operation" : \
1326 						   "Persistent connection has been closed, operation",
1327 						   status, __LINE__ );
1328 			return( FALSE );
1329 			}
1330 
1331 		/* Activate the connection to handle two more requests */
1332 		status = testTSP( cryptSession, isServer, TRUE, FALSE, FALSE );
1333 		if( status <= 0 )
1334 			return( status );
1335 		status = testTSP( cryptSession, isServer, TRUE, FALSE, FALSE );
1336 		if( status <= 0 )
1337 			return( status );
1338 		}
1339 
1340 	/* Clean up */
1341 	status = cryptDestroySession( cryptSession );
1342 	if( cryptStatusError( status ) )
1343 		{
1344 		printf( "cryptDestroySession() failed with error code %d, line %d.\n",
1345 				status, __LINE__ );
1346 		return( FALSE );
1347 		}
1348 
1349 	printf( isServer ? "SVR: %sTSP server session succeeded.\n\n" : \
1350 					   "%sTSP client session succeeded.\n\n",
1351 			persistentConnection ? "Persistent " : "" );
1352 	return( TRUE );
1353 	}
1354 
testSessionTSP(void)1355 int testSessionTSP( void )
1356 	{
1357 	return( connectTSP( CRYPT_SESSION_TSP, CRYPT_UNUSED, FALSE, FALSE ) );
1358 	}
testSessionTSPServer(void)1359 int testSessionTSPServer( void )
1360 	{
1361 	return( connectTSP( CRYPT_SESSION_TSP_SERVER, CRYPT_UNUSED, FALSE, FALSE ) );
1362 	}
testSessionTSPServerEx(const CRYPT_CONTEXT privKeyContext)1363 int testSessionTSPServerEx( const CRYPT_CONTEXT privKeyContext )
1364 	{
1365 	return( connectTSP( CRYPT_SESSION_TSP_SERVER, privKeyContext, FALSE, FALSE ) );
1366 	}
1367 
1368 /* Perform a client/server loopback test */
1369 
1370 #ifdef WINDOWS_THREADS
1371 
tspServerThread(void * dummy)1372 unsigned __stdcall tspServerThread( void *dummy )
1373 	{
1374 	acquireMutex();
1375 	connectTSP( CRYPT_SESSION_TSP_SERVER, CRYPT_UNUSED, FALSE, TRUE );
1376 	_endthreadex( 0 );
1377 	return( 0 );
1378 	}
1379 
testSessionTSPClientServer(void)1380 int testSessionTSPClientServer( void )
1381 	{
1382 	HANDLE hThread;
1383 	unsigned threadID;
1384 	int status;
1385 
1386 	/* Start the server and wait for it to initialise */
1387 	createMutex();
1388 	hThread = ( HANDLE ) _beginthreadex( NULL, 0, tspServerThread,
1389 										 NULL, 0, &threadID );
1390 	Sleep( 1000 );
1391 
1392 	/* Connect to the local server */
1393 	status = connectTSP( CRYPT_SESSION_TSP, CRYPT_UNUSED, FALSE, TRUE );
1394 	waitForThread( hThread );
1395 	destroyMutex();
1396 	return( status );
1397 	}
1398 
tspServerPersistentThread(void * dummy)1399 unsigned __stdcall tspServerPersistentThread( void *dummy )
1400 	{
1401 	acquireMutex();
1402 	connectTSP( CRYPT_SESSION_TSP_SERVER, CRYPT_UNUSED, TRUE, TRUE );
1403 	_endthreadex( 0 );
1404 	return( 0 );
1405 	}
1406 
testSessionTSPClientServerPersistent(void)1407 int testSessionTSPClientServerPersistent( void )
1408 	{
1409 	HANDLE hThread;
1410 	unsigned threadID;
1411 	int status;
1412 
1413 	/* Start the server and wait for it to initialise */
1414 	createMutex();
1415 	hThread = ( HANDLE ) _beginthreadex( NULL, 0, tspServerPersistentThread,
1416 										 NULL, 0, &threadID );
1417 	Sleep( 1000 );
1418 
1419 	/* Connect to the local server */
1420 	status = connectTSP( CRYPT_SESSION_TSP, CRYPT_UNUSED, TRUE, TRUE );
1421 	waitForThread( hThread );
1422 	destroyMutex();
1423 	return( status );
1424 	}
1425 #endif /* WINDOWS_THREADS */
1426 
1427 #endif /* TEST_SESSION || TEST_SESSION_LOOPBACK */
1428