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