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