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