1 /****************************************************************************
2 *																			*
3 *						  cryptlib Device Test Routines						*
4 *						Copyright Peter Gutmann 1997-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 /* Set the following to a nonzero value to test cryptlib's device init
20    capability.  THIS WILL ZEROISE/ERASE THE DEVICE BEING TESTED AS A PART
21    OF THE PROCESS.  All data contained in it will be destroyed.
22 
23    A number of buggy PKCS #11 devices can't be properly initialised through
24    the PKCS #11 API but require a vendor-supplied init program to be run.
25    If they're initialised via the PKCS #11 API then everything appears to
26    be fine but the device will then fail in a variety of strange ways when
27    an attempt is made to use it.  The PKCS #11 code will perform some sanity
28    checks to try and detect obvious cases of not-really-intitialised
29    initialised devices, but it can't catch every possible kind of brokenness.
30 
31    Device initialisation is always performed for native cryptographic
32    hardware devices since these are typically being subject to development
33    self-tests and need to be reset to their ground state as part of the
34    testing process.  In other words TEST_INITIALISE_DEVICE has an implicit
35    value of '1' for this device type */
36 
37 #define TEST_INITIALISE_DEVICE	0
38 
39 /* If the device is very slow (e.g. a smart card), clear the following to
40    not test the keygen capabilities of the device.  You can set this once
41    initially to generate the test keys and then re-clear it to use the
42    initially-generated keys from then on */
43 
44 #define TEST_KEYGEN
45 #if ( TEST_INITIALISE_DEVICE > 0 ) && !defined( TEST_KEYGEN )
46   #define TEST_KEYGEN			1	/* Must be 1 if initialising card */
47 #endif /* TEST_INITIALISE_DEVICE && !TEST_KEYGEN */
48 
49 /* When testing high-level functionality, it's useful to be able to disable
50    the low-level algorithm tests and go straight to the high-level tests.
51    The following define can be used to disable the algorithm tests */
52 
53 #define TEST_ALGORITHMS
54 
55 /* The default PKC algorithm that we use when generating keys in the device.
56    This is usually the universal-standard RSA, but can be switched to other
57    algorithms when we're testing different device capabilities */
58 
59 #define DEVICE_PKC_ALGO			CRYPT_ALGO_RSA
60 /* #define DEVICE_PKC_ALGO			CRYPT_ALGO_ECDSA */
61 
62 #ifdef TEST_DEVICE
63 
64 /* Note that Fortezza support was removed as of cryptlib 3.4.0, the Fortezza
65    test code is still present here for historical purposes but it's no
66    longer supported in cryptlib itself */
67 
68 /* The device code will produce a large number of warnings because of ASCII
69    <-> Unicode issues, since there aren't any PKCS #11 drivers for WinCE
70    it's not worth adding a mountain of special-case code to handle this so
71    we no-op it out under WinCE */
72 
73 #ifndef _WIN32_WCE
74 
75 /****************************************************************************
76 *																			*
77 *								Device Information							*
78 *																			*
79 ****************************************************************************/
80 
81 /* Device information tables for PKCS #11 device types.  This lists all the
82    devices we know about and can check for.  If you have a PKCS #11 device
83    that isn't listed below, you need to add an entry with its name and a
84    password and key object label usable for testing to the table, and also
85    add the name of the driver as a CRYPT_OPTION_DEVICE_PKCS11_DVRxx entry so
86    cryptlib can load the appropriate driver for it.  To add this, use the
87    updateConfig() function in testlib.c, see the code comments there for more
88    details.
89 
90    The ActivCard driver is so broken that it's incredible it works at all,
91    it's more of a PKCS #11-like API that only works if you use it in exactly
92    the same way as the single test case that ActivCard must have used to
93    evaluate it.  The Telesec driver is even more broken than that (it's so
94    bad that it doesn't even work with Netscape), it just fakes a PKCS #11
95    API while doing something completely different.
96 
97    The SEIS EID cards name their private key objects slightly differently
98    from the name used in the software-only eID driver, if you're using a
99    card-based version you need to switch the commented lines below to the
100    alternate name.
101 
102    The Rainbow iKey uses Datakey drivers, so the Datakey test below will work
103    for both Datakey cards/keys and iKeys.  The newer Rainbow USB tokens
104    (using DataKey 232 drivers) can't be usefully initialised via PKCS #11
105    but have to be initialised using the vendor utility or operations fail in
106    strange and illogical ways.  In addition the driver partially ignores
107    user-specified key attributes such as encrypt-only or sign-only and uses
108    its own internal defaults.  Finally, operations with these keys then fail
109    with a key-type-inconsistent error even though there's nothing wrong with
110    them.  The solution to these problems is to use the Datakey 201 drivers
111    (intended for Entrust compatibility, which means they actually test them
112    properly), which work properly.
113 
114    The iD2 driver implements multiple virtual slots, one for each key type,
115    so the entry is given in the extended driver::slot name format to tell
116    cryptlib which slot to use.
117 
118    To reset the Rainbow card after it locks up and stops responding to
119    commands, run /samples/cryptoki20/sample.exe, enter 1 CR, 4 CR, 5 CR,
120    7 CR 2 CR "rainbow" CR, g CR "test" CR q CR (you need to follow that
121    sequence exactly for it to work).
122 
123    To (try to) get the Eracom 3.09 CProv to work, delete the /cryptoki
124    directory (where it dumps all its config data, ignoring the settings in
125    cryptoki.ini), run ctconf.exe to set up a new device config, then
126    run ctconf -v -n0 (optionally 'ctconf -v -r0' to reinitialise the token
127    if you get an error about it already being initialised).  Then set
128    TEST_INITIALISE_DEVICE to a nonzero value and things should run OK (as
129    with the Rainbow tests, you need to follow this exactly for it to work).
130    Re-running the test with the initialised device, or trying to re-run the
131    initialisation, both fail.  The re-init reports that no login is required
132    for the token, returns an already-logged-in error if an attempt is made
133    to log in, and returns a not-logged-in error of an attempt is made to do
134    anything that needs a login.  The re-use of the initialised device fails
135    with an invalid object handle for every object that's created (that is,
136    it's possible to create any object, but any attempt to use it returns an
137    invalid object handle error).  However, retrying this on a different
138    machine with a fresh install of the 3.09 CProv jumped immediately to the
139    not-logged-in error state in which it's possible to log in, but trying to
140    perform any operation that needs a login results in a not-logged-in
141    error.
142 
143    The Eracom 2.10 CProv is usually a lot less problematic, although even
144    with that it's not possible to initialise the device in software (in
145    other words never enable TEST_INITIALISE_DEVICE), you have to run
146    'ctinit -ptest' otherwise the device will end up in a state where any
147    attempt to use an object results in a CKR_KEY_HANDLE_INVALID (so even a
148    C_CreateObject() followed immediately by a C_EncryptInit() using the
149    handle returned from C_CreateObject() returns CKR_KEY_HANDLE_INVALID).
150 
151    The Spyrus USB drivers don't get on with various drivers for other USB
152    devices such as USB printers (basic devices like USB storage keys are
153    OK).  To get the Spyrus driver to see the USB token, it may be necessary
154    to completely remove (not just disable) other USB device drivers.  The
155    Rosetta cards/USB tokens are very flaky, in general it's only possible
156    to safely generate new keys and add certs to a freshly-initialised token,
157    trying to add/update objects when there are already existing objects
158    present tends to fail with internal errors, and deleting the existing
159    objects isn't possible, the delete call succeeds but the object isn't
160    touched.  In addition with most versions of the Spyrus drivers data
161    isn't persisted to the token correctly, so some information (and even
162    complete objects) are only visible for the duration of the session that
163    created them.
164 
165    The Netscape soft-token (softokn3.dll, i.e. NSS) is a bit problematic to
166    use, it requires the presence of three additional libraries (nspr4.dll,
167    plc4.dll, and plds4.dll) in the same directory, and even then requires
168    that C_Initialize() be called with proprietary and only partially-
169    documented nonstandard arguments, see the comment in device/pkcs11_init.c
170    for more on this.  The easiest way to arrange to have all the files in
171    the right place is to chdir to "C:/Program Files/Mozilla Firefox" before
172    loading the DLL, but even this doesn't mean that it'll work properly
173    (this behaviour isn't really a bug, softokn3.dll was only ever meant to
174    be used as a crypto layer for NSS, it was never intended to be a general-
175    purpose PKCS #11 soft-token).
176 
177    The presence of a device entry in this table doesn't necessarily mean
178    that the PKCS #11 driver that it comes with functions correctly, or at
179    all.  In particular the iButton driver never really got out of beta so it
180    has some features unimplemented, and the Utimaco driver apparently has
181    some really strange bugs, as well as screwing up Windows power management
182    so that suspends either aren't possible any more or will crash apps.  At
183    the other end of the scale the Datakey (before Rainbow got to them),
184    Eracom (usually, for older versions of the driver), iD2, and nCipher
185    drivers are pretty good */
186 
187 typedef struct {
188 	const char *name;
189 	const char *description;
190 	const char *password;
191 	const char *keyLabel;	/* Existing-key name, otherwise 'Test user key' */
192 	} DEVICE_CONFIG_INFO;
193 
194 static const DEVICE_CONFIG_INFO pkcs11DeviceInfo[] = {
195 	{ "[Autodetect]", "Automatically detect device", "test", "Test user key" },
196 	{ "ActivCard Cryptoki Library", "ActivCard", "test", "Test user key" },
197 	{ "Bloomberg PKCS#11 Library", "Bloomberg", "test1234", "Test user key" },
198 	{ "Chrystoki", "Chrysalis Luna", "test", "Test user key" },
199 	{ "CryptoFlex", "CryptoFlex", "ABCD1234", "012345678901234567890123456789ME" },
200 	{ "Cryptographic Token Interface", "AET SafeSign", "test", "Test user key" },
201 	{ "Cryptoki for CardMan API", "Utimaco", "test", "Test user key" },
202 	{ "Cryptoki for eID", "Nexus soft-token", "1234", "Private key" },
203 	{ "Cryptoki for eID", "Nexus signature token", "1234", "eID private nonrepudiation key" },
204 	{ "Cryptoki for eID", "Nexus signature token", "1234", "eID private key encipherment key" },
205 	{ "Cryptoki PKCS-11", "Gemplus", "test", "Test user key" },
206 	{ "CryptoKit Extended Version", "Eutron (via Cylink)", "12345678", "Test user key" },
207 	{ "Datakey Cryptoki DLL - NETSCAPE", "Datakey pre-4.1, post-4.4 driver", "test", "Test user key" },
208 	{ "Datakey Cryptoki DLL - Version", "Datakey 4.1-4.4 driver", "test", "Test user key" },
209 	{ "Eracom Cryptoki", "Eracom", "test", "Test user key" },
210 	{ "ERACOM Software Only", "Eracom 1.x soft-token", "test", "Test user key" },
211 	{ "Software Only", "Eracom 2.x soft-token", "test", "Test user key" },
212 	{ "eToken PKCS#11", "Aladdin eToken", "test", "Test user key" },
213 	{ "G&D PKCS#11 Library", "Giesecke and Devrient", "test", "Test user key" },
214 	{ "FTSmartCard", "Feitian", "test", "1234" },
215 	{ "iButton", "Dallas iButton", "test", "Test user key" },
216 	{ "iD2 Cryptographic Library::iD2 Smart Card (PIN1)", "iD2 signature token::Slot 1", "1234", "Digital Signature" },
217 	{ "iD2 Cryptographic Library::iD2 Smart Card (PIN2)", "iD2 signature token::Slot 2", "5678", "Non Repudiation" },
218 	{ "ISG", "CryptoSwift HSM", "test", "Test user key" },
219 	{ "ISG Cryptoki API library", "CryptoSwift card", "test", "Test user key" },
220 	{ "Lynks/EES Token in SpyrusNATIVE", "Spyrus Lynks/EES", "test", "Test user key" },
221 	{ "NShield 75", "nCipher", "test", "Test user key" },
222 	{ "NSS Generic Crypto Services", "Netscape", "test", "Test user key" },
223 	{ "PKCS#11 Private Cryptoki", "GemSAFE", "1234", "Test user key" },
224 	{ "Safelayer PKCS#11", "Safelayer", "test", "Test user key" },
225 	{ "Schlumberger", "Schlumberger", "QWERTYUI", "Test user key" },
226 	{ "SignLite security module", "IBM SignLite", "test", "Test user key" },
227 	{ "SmartCard-HSM (UserPIN)", "CardContact", "123456", "rsa2k" },
228 	{ "Spyrus Rosetta", "Spyrus Rosetta", "test", "Test user key" },
229 	{ "Spyrus Lynks", "Spyrus Lynks", "test", "Test user key" },
230 	{ "Sun Metaslot", "nCipher on Solaris", "test", "Test user key" },
231 	{ "TCrypt", "Telesec", "123456", "Test user key" },
232 	{ "TrustCenter PKCS#11 Library", "GPKCS11", "12345678", "Test user key" },
233 	{ NULL, NULL, NULL }
234 	};
235 
236 /* Device information for Fortezza cards */
237 
238 #define FORTEZZA_ZEROISE_PIN		"ZeroizedCard"
239 #define FORTEZZA_SSO_DEFAULT_PIN	"Mosaic"
240 #define FORTEZZA_SSO_PIN			"test"
241 #define FORTEZZA_USER_PIN			"test"
242 
243 static const DEVICE_CONFIG_INFO fortezzaDeviceInfo = \
244 	{ "[Autodetect]", "Automatically detect device", FORTEZZA_USER_PIN, "Test user key" };
245 
246 /* Device information for CryptoAPI */
247 
248 static const DEVICE_CONFIG_INFO capiDeviceInfo[] = {
249 	{ "[Autodetect]", "Automatically detect device", "", "Encryption key" },
250 	{ "Microsoft Base Cryptographic Provider v1.0::MY", "Microsoft Base Cryptographic Provider", "", "Encryption key" },
251 	{ NULL, NULL, NULL }
252 	};
253 
254 /* Device information for generic crypto hardware */
255 
256 static const DEVICE_CONFIG_INFO hardwareDeviceInfo[] = {
257 	{ "[Autodetect]", "Automatically detect device", "test", "Test user key" },
258 	{ "Dummy device", "Dummy test device", "test", "Test user key" },
259 	{ NULL, NULL, NULL }
260 	};
261 
262 /* Data used to create certs in the device */
263 
264 static const CERT_DATA paaCertData[] = {
265 	/* Identification information */
266 	{ CRYPT_CERTINFO_COUNTRYNAME, IS_STRING, 0, "NZ" },
267 	{ CRYPT_CERTINFO_ORGANIZATIONNAME, IS_STRING, 0, "Honest Dave's PAA" },
268 	{ CRYPT_CERTINFO_ORGANIZATIONALUNITNAME, IS_STRING, 0, "Certification Policy Division" },
269 	{ CRYPT_CERTINFO_COMMONNAME, IS_STRING, 0, "Dave the PAA" },
270 
271 	/* Self-signed X.509v3 CA certificate */
272 	{ CRYPT_CERTINFO_SELFSIGNED, IS_NUMERIC, TRUE },
273 	{ CRYPT_CERTINFO_CA, IS_NUMERIC, TRUE },
274 	{ CRYPT_CERTINFO_KEYUSAGE, IS_NUMERIC,
275 	  CRYPT_KEYUSAGE_KEYCERTSIGN },
276 
277 	{ CRYPT_ATTRIBUTE_NONE, IS_VOID }
278 	};
279 
280 static const CERT_DATA cACertData[] = {
281 	/* Identification information */
282 	{ CRYPT_CERTINFO_COUNTRYNAME, IS_STRING, 0, "NZ" },
283 	{ CRYPT_CERTINFO_ORGANIZATIONNAME, IS_STRING, 0, "Dave's Wetaburgers and CA" },
284 	{ CRYPT_CERTINFO_ORGANIZATIONALUNITNAME, IS_STRING, 0, "Certification Division" },
285 	{ CRYPT_CERTINFO_COMMONNAME, IS_STRING, 0, "Dave Himself" },
286 
287 	/* Self-signed X.509v3 CA certificate */
288 	{ CRYPT_CERTINFO_SELFSIGNED, IS_NUMERIC, TRUE },
289 	{ CRYPT_CERTINFO_CA, IS_NUMERIC, TRUE },
290 	{ CRYPT_CERTINFO_KEYUSAGE, IS_NUMERIC,
291 	  CRYPT_KEYUSAGE_KEYCERTSIGN | CRYPT_KEYUSAGE_CRLSIGN },
292 
293 	{ CRYPT_ATTRIBUTE_NONE, IS_VOID }
294 	};
295 
296 static const CERT_DATA userCertData[] = {
297 	/* Identification information */
298 	{ CRYPT_CERTINFO_COUNTRYNAME, IS_STRING, 0, "NZ" },
299 	{ CRYPT_CERTINFO_ORGANIZATIONNAME, IS_STRING, 0, "Dave's Wetaburgers" },
300 	{ CRYPT_CERTINFO_COMMONNAME, IS_STRING, 0, "Dave's key" },
301 	{ CRYPT_CERTINFO_EMAIL, IS_STRING, 0, TEXT( "dave@wetaburgers.com" ) },
302 	{ CRYPT_ATTRIBUTE_CURRENT, IS_NUMERIC, CRYPT_CERTINFO_SUBJECTNAME },	/* Re-select subject DN */
303 
304 	/* X.509v3 general-purpose certificate */
305 	{ CRYPT_CERTINFO_KEYUSAGE, IS_NUMERIC,
306 	  CRYPT_KEYUSAGE_DIGITALSIGNATURE | CRYPT_KEYUSAGE_KEYENCIPHERMENT },
307 
308 	{ CRYPT_ATTRIBUTE_NONE, IS_VOID }
309 	};
310 
311 static const CERT_DATA userSigOnlyCertData[] = {
312 	/* Identification information */
313 	{ CRYPT_CERTINFO_COUNTRYNAME, IS_STRING, 0, "NZ" },
314 	{ CRYPT_CERTINFO_ORGANIZATIONNAME, IS_STRING, 0, "Dave's Wetaburgers" },
315 	{ CRYPT_CERTINFO_COMMONNAME, IS_STRING, 0, "Dave's signing key" },
316 
317 	/* X.509v3 signature-only certificate */
318 	{ CRYPT_CERTINFO_KEYUSAGE, IS_NUMERIC, CRYPT_KEYUSAGE_DIGITALSIGNATURE },
319 
320 	{ CRYPT_ATTRIBUTE_NONE, IS_VOID }
321 	};
322 
323 static const CERT_DATA userKeyAgreeCertData[] = {
324 	/* Identification information */
325 	{ CRYPT_CERTINFO_COUNTRYNAME, IS_STRING, 0, "NZ" },
326 	{ CRYPT_CERTINFO_ORGANIZATIONNAME, IS_STRING, 0, "Dave's Wetaburgers" },
327 	{ CRYPT_CERTINFO_COMMONNAME, IS_STRING, 0, "Dave's key agreement key" },
328 
329 	/* X.509v3 key agreement certificate */
330 	{ CRYPT_CERTINFO_KEYUSAGE, IS_NUMERIC, CRYPT_KEYUSAGE_KEYAGREEMENT },
331 
332 	{ CRYPT_ATTRIBUTE_NONE, IS_VOID }
333 	};
334 
335 /****************************************************************************
336 *																			*
337 *								Utility Functions							*
338 *																			*
339 ****************************************************************************/
340 
341 /* Delete leftover keys created during testing */
342 
deleteTestKey(const CRYPT_DEVICE cryptDevice,const C_STR keyName,const char * keyDescription)343 static void deleteTestKey( const CRYPT_DEVICE cryptDevice,
344 						   const C_STR keyName, const char *keyDescription )
345 	{
346 	if( cryptDeleteKey( cryptDevice, CRYPT_KEYID_NAME, \
347 						keyName ) == CRYPT_OK && keyDescription != NULL )
348 		{
349 		printf( "(Deleted a %s key object, presumably a leftover from a "
350 				"previous run).\n", keyDescription );
351 		}
352 	}
353 
354 /* Create a key and certificate in a device */
355 
createKey(const CRYPT_DEVICE cryptDevice,const CRYPT_ALGO_TYPE cryptAlgo,const char * description,const char * dumpName,const CRYPT_CONTEXT signingKey)356 static BOOLEAN createKey( const CRYPT_DEVICE cryptDevice,
357 						  const CRYPT_ALGO_TYPE cryptAlgo,
358 						  const char *description, const char *dumpName,
359 						  const CRYPT_CONTEXT signingKey )
360 	{
361 	CRYPT_CONTEXT cryptContext;
362 	CRYPT_CERTIFICATE cryptCert;
363 	BYTE certBuffer[ BUFFER_SIZE ], labelBuffer[ CRYPT_MAX_TEXTSIZE ];
364 	const BOOLEAN isCA = ( signingKey == CRYPT_UNUSED ) ? TRUE : FALSE;
365 	const CERT_DATA *certData = ( isCA ) ? cACertData : \
366 			( cryptAlgo == CRYPT_ALGO_RSA ) ? userCertData : \
367 			( cryptAlgo == CRYPT_ALGO_DSA ) ? userSigOnlyCertData : \
368 			userKeyAgreeCertData;
369 	int certificateLength, status;
370 
371 	sprintf( labelBuffer, "Test %s key", description );
372 
373 	/* Generate a key in the device */
374 	printf( "Generating a %s key in the device...", description );
375 	status = cryptDeviceCreateContext( cryptDevice, &cryptContext,
376 									   cryptAlgo );
377 	if( cryptStatusError( status ) )
378 		{
379 		printf( "\ncryptDeviceCreateContext() failed with error code %d, "
380 				"line %d.\n", status, __LINE__ );
381 		return( FALSE );
382 		}
383 	cryptSetAttributeString( cryptContext, CRYPT_CTXINFO_LABEL, labelBuffer,
384 							 strlen( labelBuffer ) );
385 	status = cryptGenerateKey( cryptContext );
386 	if( cryptStatusError( status ) )
387 		{
388 		cryptDestroyContext( cryptContext );
389 		printf( "\ncryptGenerateKey() failed with error code %d, line %d.\n",
390 				status, __LINE__ );
391 		return( FALSE );
392 		}
393 	puts( " succeeded." );
394 
395 	/* Create a certificate for the key */
396 	printf( "Generating a certificate for the key..." );
397 	status = cryptCreateCert( &cryptCert, CRYPT_UNUSED, ( isCA ) ? \
398 								CRYPT_CERTTYPE_CERTIFICATE : \
399 								CRYPT_CERTTYPE_CERTCHAIN );
400 	if( cryptStatusError( status ) )
401 		return( FALSE );
402 	status = cryptSetAttribute( cryptCert,
403 						CRYPT_CERTINFO_SUBJECTPUBLICKEYINFO, cryptContext );
404 	if( cryptStatusOK( status ) && \
405 		!addCertFields( cryptCert, certData, __LINE__ ) )
406 		return( FALSE );
407 	if( cryptStatusOK( status ) )
408 		status = cryptSignCert( cryptCert, isCA ? cryptContext : signingKey );
409 	cryptDestroyContext( cryptContext );
410 	if( cryptStatusError( status ) )
411 		{
412 		cryptDestroyCert( cryptCert );
413 		printf( "\nCreation of certificate failed with error code %d, "
414 				"line %d.\n", status, __LINE__ );
415 		return( FALSE );
416 		}
417 	puts( " succeeded." );
418 
419 	/* Dump the resulting certificate for debugging */
420 	if( dumpName != NULL )
421 		{
422 		status = cryptExportCert( certBuffer, BUFFER_SIZE, &certificateLength,
423 				isCA ? CRYPT_CERTFORMAT_CERTIFICATE : CRYPT_CERTFORMAT_CERTCHAIN,
424 				cryptCert );
425 		if( cryptStatusOK( status ) )
426 			debugDump( dumpName, certBuffer, certificateLength );
427 		}
428 
429 	/* Update the key with the certificate */
430 	printf( "Updating device with certificate..." );
431 	status = cryptAddPublicKey( cryptDevice, cryptCert );
432 	cryptDestroyCert( cryptCert );
433 	if( cryptStatusError( status ) )
434 		{
435 		printf( "\ncryptAddPublicKey() failed with error code %d, line %d.\n",
436 				status, __LINE__ );
437 		return( FALSE );
438 		}
439 	puts( " succeeded." );
440 
441 	return( TRUE );
442 	}
443 
444 /****************************************************************************
445 *																			*
446 *							Device Logon/Initialisation						*
447 *																			*
448 ****************************************************************************/
449 
450 /* Print information about a device and log in if necessary */
451 
checkLogonDevice(const CRYPT_DEVICE cryptDevice,const DEVICE_CONFIG_INFO * deviceInfo,const BOOLEAN isAutoDetect,const BOOLEAN willInitialise)452 static const DEVICE_CONFIG_INFO *checkLogonDevice( const CRYPT_DEVICE cryptDevice,
453 												   const DEVICE_CONFIG_INFO *deviceInfo,
454 												   const BOOLEAN isAutoDetect,
455 												   const BOOLEAN willInitialise )
456 	{
457 	char tokenLabel[ CRYPT_MAX_TEXTSIZE + 1 ];
458 	int loggedOn, tokenLabelSize, status;
459 
460 	/* Tell the user what we're talking to */
461 	status = cryptGetAttributeString( cryptDevice, CRYPT_DEVINFO_LABEL,
462 									  tokenLabel, &tokenLabelSize );
463 	if( cryptStatusError( status ) )
464 		puts( "(Device doesn't appear to have a label)." );
465 	else
466 		{
467 		tokenLabel[ tokenLabelSize ] = '\0';
468 		printf( "Device label is '%s'.\n", tokenLabel );
469 		}
470 
471 	/* Check whether the device corresponds to a known device.  We do this
472 	   because some devices require specific test passwords and whatnot in
473 	   order to work */
474 	if( isAutoDetect )
475 		{
476 		int i;
477 
478 		for( i = 1; deviceInfo[ i ].name != NULL; i++ )
479 			{
480 			if( tokenLabelSize == \
481 							( int ) strlen( deviceInfo[ i ].name ) && \
482 				!memcmp( deviceInfo[ i ].name, tokenLabel,
483 						 tokenLabelSize ) )
484 				{
485 				printf( "Found a match for pre-defined device '%s',\n"
486 						"  using pre-set parameters.\n",
487 						deviceInfo[ i ].description );
488 				deviceInfo = &deviceInfo[ i ];
489 				break;
490 				}
491 			}
492 		}
493 
494 	/* See if we need to authenticate ourselves */
495 	status = cryptGetAttribute( cryptDevice, CRYPT_DEVINFO_LOGGEDIN,
496 								&loggedOn );
497 	if( cryptStatusError( status ) )
498 		{
499 		puts( "Couldn't obtain device login status." );
500 		return( NULL );
501 		}
502 	if( loggedOn )
503 		{
504 		/* Device may not require a login, or has already been logged in
505 		   via a keypad or similar mechanism */
506 		puts( "Device is already logged in, skipping login." );
507 		return( deviceInfo );
508 		}
509 
510 	/* Try and log in */
511 	printf( "Logging on to the device..." );
512 	status = cryptSetAttributeString( cryptDevice,
513 							CRYPT_DEVINFO_AUTHENT_USER, deviceInfo->password,
514 							strlen( deviceInfo->password ) );
515 	if( status == CRYPT_ERROR_INITED )
516 		{
517 		/* Some devices may not require any login, in which case we're
518 		   done */
519 		puts( " device is already logged in." );
520 		return( deviceInfo );
521 		}
522 	if( status == CRYPT_ERROR_NOTINITED )
523 		{
524 		/* It's an uninitialised device, tell the user and exit */
525 		puts( " device needs to be initialised." );
526 		if( willInitialise )
527 			return( deviceInfo );
528 		printf( "cryptlib will not automatically initialise the device "
529 				"during the self-test\n  in case it contains data that "
530 				"needs to be preserved or requires special\n  steps to be "
531 				"taken before the initialisation is performed.  If you want "
532 				"to\n  initialise it, set TEST_INITIALISE_DEVICE at the top "
533 				"of\n  " __FILE__ " to a nonzero value.\n" );
534 		return( NULL );
535 		}
536 	if( cryptStatusError( status ) )
537 		{
538 		printf( "\nDevice login%s failed with error code %d, line %d.\n",
539 				( status == CRYPT_ERROR_WRONGKEY ) ? \
540 					"" : " for initialisation/setup purposes",
541 				status, __LINE__ );
542 		if( status == CRYPT_ERROR_WRONGKEY && willInitialise )
543 			{
544 			/* If we're going to initialise the card, being in the wrong (or
545 			   even totally uninitialised) state isn't an error */
546 			puts( "This may be because the device isn't in the user-"
547 				  "initialised state, in which\n  case the standard user "
548 				  "PIN can't be used to log on to it." );
549 			return( deviceInfo );
550 			}
551 		if( isAutoDetect )
552 			{
553 			puts( "This may be because the auto-detection test uses a fixed "
554 				  "login value rather\n  than one specific to the device "
555 				  "type." );
556 			}
557 		return( NULL );
558 		}
559 	puts( " succeeded." );
560 	return( deviceInfo );
561 	}
562 
563 /* Initialise a device.  Note that when doing this with a Fortezza card,
564    these operations have to be done in a more or less continuous sequence
565    (i.e. without an intervening device open call) because it's not possible
566    to escape from some of the states if the card is closed and reopened in
567    between.  In addition the PKCS #11 interface maps some of the
568    initialisation steps differently than the CI interface, so we have to
569    special-case this below */
570 
initialiseDevice(const CRYPT_DEVICE cryptDevice,const CRYPT_DEVICE_TYPE deviceType,const DEVICE_CONFIG_INFO * deviceInfo)571 static BOOLEAN initialiseDevice( const CRYPT_DEVICE cryptDevice,
572 								 const CRYPT_DEVICE_TYPE deviceType,
573 								 const DEVICE_CONFIG_INFO *deviceInfo )
574 	{
575 	const char *defaultSSOPIN = ( deviceType == CRYPT_DEVICE_FORTEZZA ) ? \
576 								FORTEZZA_SSO_DEFAULT_PIN : \
577 								deviceInfo->password;
578 	const char *ssoPIN = ( deviceType == CRYPT_DEVICE_FORTEZZA ) ? \
579 						 FORTEZZA_SSO_PIN : deviceInfo->password;
580 	const char *userPIN = deviceInfo->password;
581 	int status;
582 
583 	/* PKCS #11 doesn't distinguish between zeroisation and initialisation,
584 	   so we only perform the zeroise test if it's a Fortezza card or built-
585 	   in hardware.  The latter doesn't really distinguish between the two
586 	   either but we perform the separate zeroise/initialise to make sure
587 	   that the two work as required */
588 	if( deviceType == CRYPT_DEVICE_FORTEZZA || \
589 		deviceType == CRYPT_DEVICE_HARDWARE )
590 		{
591 		printf( "Zeroising device..." );
592 		status = cryptSetAttributeString( cryptDevice,
593 						CRYPT_DEVINFO_ZEROISE, FORTEZZA_ZEROISE_PIN,
594 						strlen( FORTEZZA_ZEROISE_PIN ) );
595 		if( cryptStatusError( status ) )
596 			{
597 			printf( "\nZeroise failed with error code %d, line %d.\n",
598 					status, __LINE__ );
599 			return( FALSE );
600 			}
601 		puts( " succeeded." );
602 		}
603 
604 	/* Initialise the device and set the SO PIN.   */
605 	printf( "Initialising device..." );
606 	status = cryptSetAttributeString( cryptDevice, CRYPT_DEVINFO_INITIALISE,
607 									  defaultSSOPIN, strlen( defaultSSOPIN ) );
608 	if( cryptStatusError( status ) )
609 		{
610 		printf( "\nCouldn't initialise device, status = %d, line %d.\n",
611 				status, __LINE__ );
612 		return( FALSE );
613 		}
614 	puts( " succeeded." );
615 	printf( "Setting SO PIN to '%s'...", ssoPIN );
616 	status = cryptSetAttributeString( cryptDevice,
617 									  CRYPT_DEVINFO_SET_AUTHENT_SUPERVISOR,
618 									  ssoPIN, strlen( ssoPIN ) );
619 	if( cryptStatusError( status ) )
620 		{
621 		printf( "\nCouldn't set SO PIN, status = %d, line %d.\n", status,
622 				__LINE__ );
623 		return( FALSE );
624 		}
625 	puts( " succeeded." );
626 
627 	/* If it's a Fortezza card, create a CA root key and install its
628 	   certificate.  We have to do it at this point because the operation is
629 	   only allowed in the SSO initialised state.  In addition we can't use
630 	   the card for this operation because certificate slot 0 is a data-only
631 	   slot (that is, it can't correspond to a key held on the card), so we
632 	   create a dummy external certificate and use that */
633 	if( deviceType == CRYPT_DEVICE_FORTEZZA )
634 		{
635 		CRYPT_CERTIFICATE cryptCert;
636 		CRYPT_CONTEXT signContext;
637 
638 		printf( "Loading PAA certificate..." );
639 		if( !loadDSAContexts( CRYPT_UNUSED, &signContext, NULL ) )
640 			return( FALSE );
641 		status = cryptCreateCert( &cryptCert, CRYPT_UNUSED,
642 								  CRYPT_CERTTYPE_CERTIFICATE );
643 		if( cryptStatusError( status ) )
644 			return( FALSE );
645 		status = cryptSetAttribute( cryptCert,
646 						CRYPT_CERTINFO_SUBJECTPUBLICKEYINFO, signContext );
647 		if( cryptStatusOK( status ) && \
648 			!addCertFields( cryptCert, paaCertData, __LINE__ ) )
649 			return( FALSE );
650 		if( cryptStatusOK( status ) )
651 			status = cryptSignCert( cryptCert, signContext );
652 		cryptDestroyContext( signContext );
653 		if( cryptStatusError( status ) )
654 			{
655 			cryptDestroyCert( cryptCert );
656 			printf( "\nCreation of certificate failed with error code %d, "
657 					"line %d.\n", status, __LINE__ );
658 			return( FALSE );
659 			}
660 		status = cryptAddPublicKey( cryptDevice, cryptCert );
661 		cryptDestroyCert( cryptCert );
662 		if( cryptStatusError( status ) )
663 			{
664 			printf( "\ncryptAddPublicKey() failed with error code %d, line "
665 					"%d.\n", status, __LINE__ );
666 			return( FALSE );
667 			}
668 		puts( " succeeded." );
669 		}
670 
671 	/* Set the user PIN and log on as the user */
672 	printf( "Setting user PIN to '%s'...", userPIN );
673 	status = cryptSetAttributeString( cryptDevice,
674 									  CRYPT_DEVINFO_SET_AUTHENT_USER,
675 									  userPIN, strlen( userPIN ) );
676 	if( cryptStatusOK( status ) )
677 		{
678 		int loggedOn;
679 
680 		/* Some devices automatically log the user in when they set the user
681 		   password, so we check to see if it's necessary to log in before we
682 		   actually do it */
683 		status = cryptGetAttribute( cryptDevice, CRYPT_DEVINFO_LOGGEDIN,
684 									&loggedOn );
685 		if( cryptStatusError( status ) )
686 			{
687 			puts( "Couldn't obtain device login status." );
688 			return( FALSE );
689 			}
690 		if( !loggedOn )
691 			{
692 			status = cryptSetAttributeString( cryptDevice,
693 											  CRYPT_DEVINFO_AUTHENT_USER,
694 											  userPIN, strlen( userPIN ) );
695 			}
696 		}
697 	if( cryptStatusError( status ) )
698 		{
699 		printf( "\nCouldn't set user PIN/log on as user, status = %d, line "
700 				"%d.\n", status, __LINE__ );
701 		return( FALSE );
702 		}
703 	puts( " succeeded." );
704 
705 	return( TRUE );
706 	}
707 
708 /****************************************************************************
709 *																			*
710 *									Device Tests							*
711 *																			*
712 ****************************************************************************/
713 
714 /* Test the general capabilities of a device */
715 
testDeviceCapabilities(const CRYPT_DEVICE cryptDevice,const char * deviceName,const BOOLEAN isWriteProtected)716 static BOOLEAN testDeviceCapabilities( const CRYPT_DEVICE cryptDevice,
717 									   const char *deviceName,
718 									   const BOOLEAN isWriteProtected )
719 	{
720 	CRYPT_ALGO_TYPE cryptAlgo;
721 	int testCount = 0, failCount = 0;
722 
723 	printf( "Checking %s capabilities...\n", deviceName );
724 	for( cryptAlgo = CRYPT_ALGO_FIRST_CONVENTIONAL;
725 		 cryptAlgo <= CRYPT_ALGO_LAST; cryptAlgo++ )
726 		{
727 		if( cryptStatusOK( cryptDeviceQueryCapability( cryptDevice,
728 													   cryptAlgo, NULL ) ) )
729 			{
730 			testCount++;
731 			if( !testLowlevel( cryptDevice, cryptAlgo, isWriteProtected ) )
732 				{
733 				/* The test failed, we don't exit at this point but only
734 				   remember that there was a problem since we want to test
735 				   every possible algorithm */
736 				failCount++;
737 				}
738 			}
739 		}
740 
741 	if( isWriteProtected )
742 		puts( "No tests were performed since the device is write-protected." );
743 	else
744 		{
745 		if( failCount )
746 			printf( "%d of %d test%s failed.\n", failCount, testCount,
747 					( testCount > 1 ) ? "s" : "" );
748 		else
749 			puts( "Device capabilities test succeeded." );
750 		}
751 
752 	return( ( failCount == testCount ) ? FALSE : TRUE );
753 	}
754 
755 /* Test the high-level functionality provided by a device */
756 
testPersistentObject(const CRYPT_DEVICE cryptDevice)757 static BOOLEAN testPersistentObject( const CRYPT_DEVICE cryptDevice )
758 	{
759 	CRYPT_ALGO_TYPE cryptAlgo = CRYPT_ALGO_HMAC_SHA1;
760 	CRYPT_CONTEXT cryptContext;
761 	int status;
762 
763 	printf( "Loading a persistent symmetric key into the device..." );
764 
765 	/* Find an encryption algorithm that we can use and create a context in
766 	   the device */
767 	status = cryptDeviceQueryCapability( cryptDevice, cryptAlgo, NULL );
768 	if( cryptStatusError( status ) )
769 		{
770 		cryptAlgo = CRYPT_ALGO_3DES;
771 		status = cryptDeviceQueryCapability( cryptDevice, cryptAlgo, NULL );
772 		}
773 	if( cryptStatusOK( status ) )
774 		status = cryptDeviceCreateContext( cryptDevice, &cryptContext,
775 										   cryptAlgo );
776 	if( cryptStatusError( status ) )
777 		{
778 		printf( "\nCouldn't create conventional-encryption context in "
779 				"device, status = %d, line %d.\n", status, __LINE__ );
780 		return( FALSE );
781 		}
782 
783 	/* Make it a persistent object and load a key */
784 	status = cryptSetAttributeString( cryptContext, CRYPT_CTXINFO_LABEL,
785 									  SYMMETRIC_KEY_LABEL,
786 									  strlen( SYMMETRIC_KEY_LABEL ) );
787 	if( cryptStatusOK( status ) )
788 		status = cryptSetAttribute( cryptContext, CRYPT_CTXINFO_PERSISTENT,
789 									TRUE );
790 	if( cryptStatusError( status ) )
791 		{
792 		printf( "\nCouldn't make device context persistent, status = %d, "
793 				"line %d.\n", status, __LINE__ );
794 		return( FALSE );
795 		}
796 	status = cryptGenerateKey( cryptContext );
797 	if( cryptStatusError( status ) )
798 		{
799 		printf( "\nCouldn't load key into persistent context, status = %d, "
800 				"line %d.\n", status, __LINE__ );
801 		return( FALSE );
802 		}
803 	puts( " succeeded." );
804 
805 	/* Destroy the context.  Since it's persistent, it'll still be present
806 	   in the device */
807 	cryptDestroyContext( cryptContext );
808 
809 	/* Recreate the object from the device */
810 	printf( "Reading back symmetric key..." );
811 	status = cryptGetKey( cryptDevice, &cryptContext, CRYPT_KEYID_NAME,
812 						  SYMMETRIC_KEY_LABEL, NULL );
813 	if( cryptStatusError( status ) )
814 		{
815 		printf( "\nRead of symmetric key failed, status = %d, line %d.\n",
816 				status, __LINE__ );
817 		return( FALSE );
818 		}
819 	puts( " succeeded." );
820 
821 	/* Re-destroy it and make sure that it's still there afterwards.  This
822 	   tests the persistence of read-back objects vs. created objects */
823 	cryptDestroyContext( cryptContext );
824 	printf( "Re-reading back symmetric key..." );
825 	status = cryptGetKey( cryptDevice, &cryptContext, CRYPT_KEYID_NAME,
826 						  SYMMETRIC_KEY_LABEL, NULL );
827 	if( cryptStatusError( status ) )
828 		{
829 		printf( "\nRe-read of symmetric key failed, status = %d, line %d.\n",
830 				status, __LINE__ );
831 		return( FALSE );
832 		}
833 	puts( " succeeded." );
834 
835 	/* Perform an encrypt/decrypt test with the recreated object */
836 	printf( "Performing encryption test with recovered key..." );
837 	status = testCrypt( cryptContext, cryptContext, NULL, TRUE, FALSE );
838 	if( cryptStatusError( status ) )
839 		return( FALSE );
840 	puts( " succeeded." );
841 
842 	/* Clean up.  Unlike the public/private keys which are reused for
843 	   various tests, this object isn't really useful for anything else so
844 	   we always clean it up once we're done */
845 	cryptDestroyContext( cryptContext );
846 	deleteTestKey( cryptDevice, SYMMETRIC_KEY_LABEL, NULL );
847 	return( TRUE );
848 	}
849 
testDeviceHighlevel(const CRYPT_DEVICE cryptDevice,const CRYPT_DEVICE_TYPE deviceType,const char * keyLabel,const char * password,const BOOLEAN isWriteProtected)850 static BOOLEAN testDeviceHighlevel( const CRYPT_DEVICE cryptDevice,
851 									const CRYPT_DEVICE_TYPE deviceType,
852 									const char *keyLabel,
853 									const char *password,
854 									const BOOLEAN isWriteProtected )
855 	{
856 	CRYPT_CONTEXT pubKeyContext, privKeyContext, sigKeyContext;
857 	int status;
858 
859 #ifdef TEST_KEYGEN
860 	if( !isWriteProtected )
861 		{
862 		const CRYPT_ALGO_TYPE cryptAlgo = \
863 						( deviceType == CRYPT_DEVICE_FORTEZZA ) ? \
864 						CRYPT_ALGO_DSA : DEVICE_PKC_ALGO;
865 
866 		if( deviceType != CRYPT_DEVICE_CRYPTOAPI )
867 			{
868 			/* Create a CA key in the device */
869 			if( !createKey( cryptDevice, cryptAlgo, "CA",
870 							( deviceType == CRYPT_DEVICE_PKCS11 ) ? \
871 							"dp_cacert" : "df_cacert", CRYPT_UNUSED ) )
872 				return( FALSE );
873 
874 			/* Read back the CA key for use in generating end entity certs */
875 			status = cryptGetPrivateKey( cryptDevice, &sigKeyContext,
876 										 CRYPT_KEYID_NAME,
877 										 TEXT( "Test CA key" ), NULL );
878 			if( status == CRYPT_ERROR_NOTFOUND )
879 				{
880 				/* If we're using a PKCS #11 device that doesn't support
881 				   object labels then we have to use the alternate read
882 				   method via the certificate CN.  This requires enabling
883 				   PKCS11_FIND_VIA_CRYPTLIB in device/pkcs11_rw.c */
884 				assert( cACertData[ 3 ].type == CRYPT_CERTINFO_COMMONNAME );
885 				status = cryptGetPrivateKey( cryptDevice, &sigKeyContext,
886 											 CRYPT_KEYID_NAME,
887 											 cACertData[ 3 ].stringValue,
888 											 NULL );
889 				}
890 			}
891 		else
892 			{
893 			/* CryptoAPI can only store one private key per provider so we
894 			   can't have both a CA key and user key in the same "device".
895 			   Because of this we have to use the fixed CA key to issue the
896 			   certificate */
897 			status = getPrivateKey( &sigKeyContext, CA_PRIVKEY_FILE,
898 									CA_PRIVKEY_LABEL, TEST_PRIVKEY_PASSWORD );
899 			}
900 		if( cryptStatusError( status ) )
901 			{
902 			printf( "\nRead of CA key failed with error code %d, line %d.\n",
903 					status, __LINE__ );
904 			return( FALSE );
905 			}
906 
907 		/* Create end-entity certificate(s) for keys using the previously-
908 		   generated CA key.  If it's a Fortezza card and we're using KEA we
909 		   have to generate two sets of keys/certs, one for signing and one
910 		   for encryption */
911 		status = createKey( cryptDevice, cryptAlgo, "user",
912 							( deviceType == CRYPT_DEVICE_PKCS11 ) ? \
913 							"dp_usrcert" : "df_usrcert", sigKeyContext );
914 #ifdef USE_KEA
915 		if( status && deviceType == CRYPT_DEVICE_FORTEZZA )
916 			status = createKey( cryptDevice, CRYPT_ALGO_KEA, "KEA",
917 								"df_keacert", sigKeyContext );
918 #endif /* USE_KEA */
919 		cryptDestroyContext( sigKeyContext );
920 		if( !status )
921 			return( FALSE );
922 		}
923 	else
924 #endif /* TEST_KEYGEN */
925 		{
926 		puts( "Skipping key generation test, this assumes that the device "
927 			  "contains pre-\n  existing keys." );
928 		}
929 
930 	/* See whether there are any existing keys or certs.  Some tokens have
931 	   these built in and don't allow anything new to be created, after this
932 	   point the handling is somewhat special-case but we can at least report
933 	   their presence.  Although generally we can re-use a private key
934 	   context for both public and private operations, some devices or drivers
935 	   (and by logical extension thereof the cryptlib kernel) don't allow
936 	   public-key ops with private keys so we have to eplicitly handle public
937 	   and private keys.  This gets somewhat messy because some devices don't
938 	   have public keys but allow public-key ops with their private keys,
939 	   while others separate public and private keys and don't allow the
940 	   private key to do public-key ops */
941 	status = cryptGetPublicKey( cryptDevice, &pubKeyContext,
942 								CRYPT_KEYID_NAME, keyLabel );
943 	if( cryptStatusOK( status ) )
944 		{
945 		int value;
946 
947 		puts( "Found a public key in the device, details follow..." );
948 		printCertChainInfo( pubKeyContext );
949 		if( cryptStatusOK( \
950 				cryptGetAttribute( pubKeyContext,
951 								   CRYPT_CERTINFO_SELFSIGNED, &value ) ) && \
952 			value )
953 			{
954 			/* It's a self-signed certificate/certificate chain, make sure
955 			   that it's valid.  Because it's probably not trusted, we make
956 			   it temporarily implicitly trusted in order for the sig.check
957 			   to succeed */
958 			status = cryptGetAttribute( pubKeyContext,
959 								CRYPT_CERTINFO_TRUSTED_IMPLICIT, &value );
960 			if( cryptStatusOK( status ) )
961 				status = cryptSetAttribute( pubKeyContext,
962 									CRYPT_CERTINFO_TRUSTED_IMPLICIT, 1 );
963 			if( cryptStatusOK( status ) )
964 				status = cryptCheckCert( pubKeyContext, CRYPT_UNUSED );
965 			if( cryptStatusError( status ) )
966 				{
967 				printf( "Signature on certificate is invalid, status %d, "
968 						"line %d.\n", status, __LINE__ );
969 				return( FALSE );
970 				}
971 			cryptSetAttribute( pubKeyContext,
972 							   CRYPT_CERTINFO_TRUSTED_IMPLICIT, value );
973 			}
974 		}
975 	else
976 		{
977 		puts( "Error: Couldn't locate public key in device." );
978 		pubKeyContext = CRYPT_UNUSED;
979 		}
980 	status = cryptGetPrivateKey( cryptDevice, &privKeyContext,
981 								 CRYPT_KEYID_NAME, keyLabel, NULL );
982 	if( cryptStatusOK( status ) )
983 		{
984 		puts( "Found a private key in the device, details follow..." );
985 		printCertChainInfo( privKeyContext );
986 		if( pubKeyContext == CRYPT_UNUSED )
987 			{
988 			/* No explicit public key found, try using the private key for
989 			   both key types */
990 			puts( "No public key found, attempting to continue using the "
991 				  "private key as both a\n  public and a private key." );
992 			pubKeyContext = privKeyContext;
993 			}
994 		}
995 	else
996 		{
997 		puts( "Error: Couldn't locate private key in device." );
998 		privKeyContext = CRYPT_UNUSED;
999 		}
1000 	sigKeyContext = privKeyContext;
1001 	if( deviceType == CRYPT_DEVICE_FORTEZZA )
1002 		{
1003 		cryptDestroyContext( pubKeyContext );	/* pubK is sig.only */
1004 		status = cryptGetPrivateKey( cryptDevice, &privKeyContext,
1005 									 CRYPT_KEYID_NAME, "Test KEA key", NULL );
1006 		if( cryptStatusOK( status ) )
1007 			{
1008 			puts( "Found a key agreement key in the device, details follow..." );
1009 			printCertChainInfo( privKeyContext );
1010 			pubKeyContext = privKeyContext;		/* Fortezza allows both uses */
1011 			}
1012 		else
1013 			{
1014 			pubKeyContext = CRYPT_UNUSED;
1015 			privKeyContext = CRYPT_UNUSED;
1016 			}
1017 		}
1018 
1019 	/* If we got something, try some simple operations with it */
1020 	if( pubKeyContext != CRYPT_UNUSED )
1021 		{
1022 		char emailAddress[ CRYPT_MAX_TEXTSIZE + 1 ];
1023 		int length;
1024 
1025 		if( !testEnvelopePKCCryptEx( pubKeyContext, cryptDevice ) )
1026 			{
1027 			if( deviceType == CRYPT_DEVICE_HARDWARE )
1028 				{
1029 				puts( "\nEnveloping test failed when using the built-in "
1030 					  "cryptographic hardware device.\nIf this is an "
1031 					  "emulated device that doesn't fully implement "
1032 					  "public/private-key\nencryption and the test failed "
1033 					  "with a CRYPT_ERROR_BADDATA then this isn't\na fatal "
1034 					  "error, it simply means that cryptlib has detected "
1035 					  "that the emulation\nisn't performing a genuine "
1036 					  "crypto operation." );
1037 				}
1038 			return( FALSE );
1039 			}
1040 		if( !testCMSEnvelopePKCCryptEx( pubKeyContext, cryptDevice,
1041 										password, NULL ) )
1042 			return( FALSE );
1043 		cryptSetAttribute( pubKeyContext, CRYPT_ATTRIBUTE_CURRENT,
1044 						   CRYPT_CERTINFO_SUBJECTALTNAME );
1045 		status = cryptGetAttributeString( pubKeyContext, CRYPT_CERTINFO_EMAIL,
1046 										  emailAddress, &length );
1047 		if( cryptStatusError( status ) )
1048 			{
1049 			printf( "Couldn't read recipient address from certificate, "
1050 					"status %d, line %d.\n", status, __LINE__ );
1051 			return( FALSE );
1052 			}
1053 		emailAddress[ length ] = '\0';
1054 		if( !testCMSEnvelopePKCCryptEx( CRYPT_UNUSED, cryptDevice,
1055 										password, emailAddress ) )
1056 			return( FALSE );
1057 		}
1058 	else
1059 		{
1060 		puts( "Public-key enveloping tests skipped because no key was "
1061 			  "available.\n" );
1062 		}
1063 	if( sigKeyContext != CRYPT_UNUSED )
1064 		{
1065 		if( !testCMSEnvelopeSignEx( sigKeyContext ) )
1066 			return( FALSE );
1067 		}
1068 	else
1069 		{
1070 		puts( "Signed enveloping tests skipped because no key was "
1071 			  "available." );
1072 		}
1073 
1074 	/* Test persistent (non-public-key) object creation */
1075 #ifdef TEST_KEYGEN
1076 	if( !isWriteProtected )
1077 		{
1078 		if( !testPersistentObject( cryptDevice ) )
1079 			return( FALSE );
1080 		}
1081 #endif /* TEST_KEYGEN */
1082 
1083 	/* Clean up */
1084 	if( pubKeyContext == CRYPT_UNUSED && sigKeyContext == CRYPT_UNUSED )
1085 		return( FALSE );
1086 	if( privKeyContext != CRYPT_UNUSED )
1087 		cryptDestroyContext( privKeyContext );
1088 	if( sigKeyContext != CRYPT_UNUSED && privKeyContext != sigKeyContext )
1089 		cryptDestroyContext( sigKeyContext );
1090 	if( pubKeyContext != CRYPT_UNUSED && pubKeyContext != privKeyContext )
1091 		cryptDestroyContext( pubKeyContext );
1092 	return( TRUE );
1093 	}
1094 
1095 /* General device test routine */
1096 
testCryptoDevice(const CRYPT_DEVICE_TYPE deviceType,const char * deviceName,const DEVICE_CONFIG_INFO * deviceInfo)1097 static int testCryptoDevice( const CRYPT_DEVICE_TYPE deviceType,
1098 							 const char *deviceName,
1099 							 const DEVICE_CONFIG_INFO *deviceInfo )
1100 	{
1101 	CRYPT_DEVICE cryptDevice;
1102 	BOOLEAN isWriteProtected = FALSE, isAutoDetect = FALSE;
1103 	BOOLEAN testResult = FALSE, partialSuccess = FALSE;
1104 	int status;
1105 
1106 	/* Open a connection to the device */
1107 	if( deviceType == CRYPT_DEVICE_PKCS11 || \
1108 		deviceType == CRYPT_DEVICE_CRYPTOAPI || \
1109 		deviceType == CRYPT_DEVICE_HARDWARE )
1110 		{
1111 		if( !memcmp( deviceInfo->name, "[A", 2 ) )
1112 			{
1113 			printf( "\nTesting %s with autodetection...\n", deviceName );
1114 			isAutoDetect = TRUE;
1115 			}
1116 		else
1117 			printf( "\nTesting %s %s...\n", deviceInfo->description, deviceName );
1118 		status = cryptDeviceOpen( &cryptDevice, CRYPT_UNUSED, deviceType,
1119 								  deviceInfo->name );
1120 		}
1121 	else
1122 		{
1123 		printf( "\nTesting %s...\n", deviceName );
1124 		status = cryptDeviceOpen( &cryptDevice, CRYPT_UNUSED, deviceType,
1125 								  deviceName );
1126 		}
1127 	if( status == CRYPT_ERROR_PARAM2 )
1128 		{
1129 		puts( "Support for this device type isn't enabled in this build of "
1130 			  "cryptlib." );
1131 		return( CRYPT_ERROR_NOTAVAIL );	/* Device access not available */
1132 		}
1133 	if( cryptStatusError( status ) )
1134 		{
1135 		if( status == CRYPT_ERROR_PARAM3 || status == CRYPT_ERROR_NOTFOUND )
1136 			puts( "Crypto device not detected, skipping test." );
1137 		else
1138 			printf( "cryptDeviceOpen() failed with error code %d, line %d.\n",
1139 					status, __LINE__ );
1140 		return( FALSE );
1141 		}
1142 
1143 	/* If it's one of the smarter classes of device, authenticate ourselves to
1144 	   the device, which is usually required in order to allow it to be used
1145 	   fully */
1146 	if( deviceType == CRYPT_DEVICE_PKCS11 || \
1147 		deviceType == CRYPT_DEVICE_FORTEZZA || \
1148 		deviceType == CRYPT_DEVICE_HARDWARE )
1149 		{
1150 		deviceInfo = checkLogonDevice( cryptDevice, deviceInfo, isAutoDetect,
1151 									   TEST_INITIALISE_DEVICE );
1152 		if( deviceInfo == NULL )
1153 			{
1154 			cryptDeviceClose( cryptDevice );
1155 			return( FALSE );
1156 			}
1157 		}
1158 
1159 	/* Write-protected devices won't allow contexts to be created in them,
1160 	   before we try the general device capabilities test we make sure that
1161 	   we can actually perform the operation */
1162 	if( deviceType == CRYPT_DEVICE_PKCS11 )
1163 		{
1164 		CRYPT_CONTEXT cryptContext;
1165 
1166 		/* Try and create a DES object.  The following check for read-only
1167 		   devices always works because the device object ACL is applied at
1168 		   a much higher level than any device capability checking, the
1169 		   device will never even see the create object message if it's
1170 		   write-protected so all we have to do is make sure that whatever
1171 		   we create is ephemeral */
1172 		status = cryptDeviceCreateContext( cryptDevice, &cryptContext,
1173 										   CRYPT_ALGO_3DES );
1174 		if( cryptStatusOK( status ) )
1175 			cryptDestroyContext( cryptContext );
1176 		if( status == CRYPT_ERROR_PERMISSION )
1177 			isWriteProtected = TRUE;
1178 		}
1179 
1180 	/* To force the code not to try to create keys and certs in a writeable
1181 	   device, uncomment the following line of code.  This requires that keys/
1182 	   certs of the required type are already present in the device */
1183 /*	KLUDGE_WARN( "write-protect status" );
1184 	isWriteProtected = TRUE; */
1185 #ifdef TEST_KEYGEN
1186 	if( !isWriteProtected )
1187 		{
1188 		/* If it's a device that we can initialise, go through a full
1189 		   initialisation.  Note that if this we're using built-in
1190 		   cryptographic hardware then we always perform the initialisation
1191 		   because we're typically doing this as a development self-test and
1192 		   need to restore the hardware to the ground state before we can
1193 		   continue */
1194 		if( deviceType != CRYPT_DEVICE_CRYPTOAPI && \
1195 			( TEST_INITIALISE_DEVICE || deviceType == CRYPT_DEVICE_HARDWARE ) )
1196 			{
1197 			status = initialiseDevice( cryptDevice, deviceType,
1198 									   deviceInfo );
1199 			if( status == FALSE )
1200 				{
1201 				cryptDeviceClose( cryptDevice );
1202 				return( FALSE );
1203 				}
1204 			}
1205 		else
1206 			{
1207 			/* There may be test keys lying around from an earlier run, in
1208 			   which case we try to delete them to make sure they won't
1209 			   interfere with the current one */
1210 			deleteTestKey( cryptDevice, "Test CA key", "CA" );
1211 			deleteTestKey( cryptDevice, deviceInfo->keyLabel, "user" );
1212 			if( deviceType == CRYPT_DEVICE_PKCS11 )
1213 				{
1214 				deleteTestKey( cryptDevice, RSA_PUBKEY_LABEL, "RSA public" );
1215 				deleteTestKey( cryptDevice, RSA_PRIVKEY_LABEL, "RSA private" );
1216 				deleteTestKey( cryptDevice, DSA_PUBKEY_LABEL, "DSA public" );
1217 				deleteTestKey( cryptDevice, DSA_PRIVKEY_LABEL, "DSA private" );
1218 				deleteTestKey( cryptDevice, SYMMETRIC_KEY_LABEL, "symmetric" );
1219 				assert( cACertData[ 3 ].type == CRYPT_CERTINFO_COMMONNAME );
1220 				deleteTestKey( cryptDevice, cACertData[ 3 ].stringValue,
1221 							   "CA-cert" );
1222 				assert( userCertData[ 2 ].type == CRYPT_CERTINFO_COMMONNAME );
1223 				deleteTestKey( cryptDevice, userCertData[ 2 ].stringValue,
1224 							   "user-cert" );
1225 				assert( userSigOnlyCertData[ 2 ].type == CRYPT_CERTINFO_COMMONNAME );
1226 				deleteTestKey( cryptDevice,
1227 							   userSigOnlyCertData[ 2 ].stringValue,
1228 							   "sig-only-cert" );
1229 				assert( userKeyAgreeCertData[ 2 ].type == CRYPT_CERTINFO_COMMONNAME );
1230 				deleteTestKey( cryptDevice,
1231 							   userKeyAgreeCertData[ 2 ].stringValue,
1232 							   "keyagree-only-cert" );
1233 				}
1234 			if( deviceType == CRYPT_DEVICE_FORTEZZA )
1235 				deleteTestKey( cryptDevice, "Test KEA key", "KEA" );
1236 			if( deviceType == CRYPT_DEVICE_CRYPTOAPI )
1237 				{
1238 				deleteTestKey( cryptDevice, "Encryption key", "RSA private" );
1239 				deleteTestKey( cryptDevice, "Signature key", "secondary RSA private" );
1240 				}
1241 			}
1242 		}
1243 #endif /* TEST_KEYGEN */
1244 
1245 #ifdef TEST_DH
1246 	return( testLowlevel( cryptDevice, CRYPT_ALGO_DH, FALSE ) );
1247 #endif /* TEST_DH */
1248 
1249 	/* Report what the device can do.  This is intended mostly for simple
1250 	   crypto accelerators and may fail with for devices that work only
1251 	   with the higher-level functions centered around certificates,
1252 	   signatures,and key wrapping, so we skip the tests for devices that
1253 	   allow only high-level access */
1254 #ifdef TEST_ALGORITHMS
1255 	if( deviceType != CRYPT_DEVICE_FORTEZZA )
1256 		testResult = testDeviceCapabilities( cryptDevice, deviceName,
1257 											 isWriteProtected );
1258 #else
1259 	puts( "Skipping device algorithm tests." );
1260 #endif /* TEST_ALGORITHMS */
1261 
1262 	/* If it's a smart device, try various device-specific operations */
1263 	if( deviceType == CRYPT_DEVICE_FORTEZZA || \
1264 		deviceType == CRYPT_DEVICE_PKCS11 || \
1265 		deviceType == CRYPT_DEVICE_CRYPTOAPI || \
1266 		deviceType == CRYPT_DEVICE_HARDWARE )
1267 		{
1268 		partialSuccess = testDeviceHighlevel( cryptDevice, deviceType,
1269 								deviceInfo->keyLabel, deviceInfo->password,
1270 								isWriteProtected );
1271 		}
1272 
1273 	/* Clean up */
1274 	status = cryptDeviceClose( cryptDevice );
1275 	if( cryptStatusError( status ) )
1276 		{
1277 		printf( "cryptDeviceClose() failed with error code %d, line %d.\n",
1278 				status, __LINE__ );
1279 		return( FALSE );
1280 		}
1281 	if( !testResult && !partialSuccess )
1282 		return( FALSE );
1283 	if( testResult && partialSuccess )
1284 		printf( "\n%s tests succeeded.\n\n", deviceName );
1285 	else
1286 		printf( "\nSome %s tests succeeded.\n\n", deviceName );
1287 	return( TRUE );
1288 	}
1289 
testDevices(void)1290 int testDevices( void )
1291 	{
1292 	int i, status;
1293 
1294 	/* Test PKCS #11 devices */
1295 #if 1
1296 	for( i = 0; pkcs11DeviceInfo[ i ].name != NULL; i++ )
1297 		{
1298 		status = testCryptoDevice( CRYPT_DEVICE_PKCS11, "PKCS #11 crypto token",
1299 								   &pkcs11DeviceInfo[ i ] );
1300 		if( cryptStatusError( status ) && \
1301 			!( status == CRYPT_ERROR_NOTAVAIL || \
1302 			   ( i == 0 && status == CRYPT_ERROR_WRONGKEY ) ) )
1303 			return( status );
1304 		}
1305 #endif /* 0 */
1306 
1307 	/* Test generic crypto hardware interface */
1308 #if 0
1309 	for( i = 0; hardwareDeviceInfo[ i ].name != NULL; i++ )
1310 		{
1311 		status = testCryptoDevice( CRYPT_DEVICE_HARDWARE, "generic crypto hardware",
1312 								   &hardwareDeviceInfo[ i ] );
1313 		if( cryptStatusError( status ) && \
1314 			!( status == CRYPT_ERROR_NOTAVAIL || \
1315 			   ( i == 0 && status == CRYPT_ERROR_WRONGKEY ) ) )
1316 			return( status );
1317 		}
1318 #endif /* 0 */
1319 
1320 #if 0	/* For test purposes only to check CAPI data, don't use the CAPI code */
1321 #ifdef __WINDOWS__
1322 	for( i = 0; capiDeviceInfo[ i ].name != NULL; i++ )
1323 		{
1324 		status = testCryptoDevice( CRYPT_DEVICE_CRYPTOAPI, "Microsoft CryptoAPI",
1325 								   &capiDeviceInfo[ i ] );
1326 		if( cryptStatusError( status ) && \
1327 			!( status == CRYPT_ERROR_NOTAVAIL || \
1328 			   ( i == 0 && status == CRYPT_ERROR_WRONGKEY ) ) )
1329 			return( status );
1330 		}
1331 #endif /* __WINDOWS__ */
1332 #endif /* 0 */
1333 	putchar( '\n' );
1334 	return( TRUE );
1335 	}
1336 
1337 /****************************************************************************
1338 *																			*
1339 *						Full Device Initialisation Test						*
1340 *																			*
1341 ****************************************************************************/
1342 
1343 /* The following code takes two unitialised devices and turns one into a
1344    fully initialised CA device, which then runs a PnP PKI session that turns
1345    the other into a fully initialised user device.
1346 
1347    The following configuration options can be used to change the beaviour of
1348    the self-test, for example to run it on the local machine in loopback mode
1349    vs. running on two distinct machines.  Defining an IP address (or host
1350    name) for SERVER_MACHINE_ADDRESS will have the client connect to that
1351    address instead of running a local loopback test */
1352 
1353 #if 0
1354   #define SERVER_MACHINE_ADDRESS	"161.5.99.22"
1355   #define SERVER_MACHINE_PORT		4080
1356   #define CLIENT_DEVICE_TYPE		CRYPT_DEVICE_FORTEZZA
1357   #define SERVER_DEVICE_TYPE		CRYPT_DEVICE_FORTEZZA
1358   #define CLIENT_ID					"25CHS-UDQBU-BPASM"
1359   #define CLIENT_AUTHENTICATOR		"5ZCJ8-34A5C-YSXRD-C9EME"
1360   #define CLIENT_TOKEN_SLOT			CRYPT_USE_DEFAULT
1361   #define NET_TIMEOUT				300
1362 #else
1363   #define SERVER_MACHINE_ADDRESS	"localhost"
1364   #define SERVER_MACHINE_PORT		80
1365   #define CLIENT_DEVICE_TYPE		CRYPT_DEVICE_FORTEZZA
1366   #define SERVER_DEVICE_TYPE		CRYPT_DEVICE_FORTEZZA
1367   #define CLIENT_TOKEN_SLOT			1
1368   #define NET_TIMEOUT				CRYPT_USE_DEFAULT
1369 #endif /* Loopback vs. general test */
1370 
1371 /* Default PIN values */
1372 
1373 #if CLIENT_DEVICE_TYPE == CRYPT_DEVICE_FORTEZZA
1374   #define DEFAULT_SSO_PIN	FORTEZZA_SSO_DEFAULT_PIN
1375 #else
1376   #define DEFAULT_SSO_PIN	"0000"
1377 #endif /* Fortezza vs. PKCS #11 default SSO PINs */
1378 #define SSO_PIN			"0000"
1379 #define USER_PIN		"0000"
1380 
1381 /* Set up a client/server to connect locally (usually) or to a custom
1382    address and port if we're running on distinct machines.  For the client
1383    this simply tells it where to connect, for the server in loopback mode
1384    this binds it to the local address so that we don't inadvertently open
1385    up outside ports */
1386 
setConnectInfo(const CRYPT_SESSION cryptSession,const char * address,const int port,const int timeout)1387 static BOOLEAN setConnectInfo( const CRYPT_SESSION cryptSession,
1388 							   const char *address, const int port,
1389 							   const int timeout )
1390 	{
1391 	int status;
1392 
1393 	status = cryptSetAttributeString( cryptSession,
1394 									  CRYPT_SESSINFO_SERVER_NAME,
1395 									  address,  strlen( address ) );
1396 	if( cryptStatusOK( status ) )
1397 		status = cryptSetAttribute( cryptSession,
1398 									CRYPT_SESSINFO_SERVER_PORT, port );
1399 	if( cryptStatusOK( status ) && timeout != CRYPT_USE_DEFAULT )
1400 		{
1401 		cryptSetAttribute( cryptSession, CRYPT_OPTION_NET_READTIMEOUT,
1402 						   NET_TIMEOUT );
1403 		status = cryptSetAttribute( cryptSession,
1404 									CRYPT_OPTION_NET_WRITETIMEOUT,
1405 									NET_TIMEOUT );
1406 		}
1407 	if( cryptStatusError( status ) )
1408 		{
1409 		printf( "cryptSetAttribute/AttributeString() failed with error code "
1410 				"%d, line %d.\n", status, __LINE__ );
1411 		return( FALSE );
1412 		}
1413 
1414 	return( TRUE );
1415 	}
1416 
1417 /* Create a CA certificate in a device */
1418 
1419 static const CERT_DATA rootCACertData[] = {
1420 	/* Identification information */
1421 	{ CRYPT_CERTINFO_COUNTRYNAME, IS_STRING, 0, "AT" },
1422 	{ CRYPT_CERTINFO_ORGANIZATIONNAME, IS_STRING, 0, "IAEA" },
1423 	{ CRYPT_CERTINFO_ORGANIZATIONALUNITNAME, IS_STRING, 0, "SGTIE" },
1424 	{ CRYPT_CERTINFO_COMMONNAME, IS_STRING, 0, "IAEA CA root" },
1425 
1426 	/* Self-signed X.509v3 CA certificate */
1427 	{ CRYPT_CERTINFO_SELFSIGNED, IS_NUMERIC, TRUE },
1428 	{ CRYPT_CERTINFO_CA, IS_NUMERIC, TRUE },
1429 	{ CRYPT_CERTINFO_KEYUSAGE, IS_NUMERIC,
1430 	  CRYPT_KEYUSAGE_KEYCERTSIGN | CRYPT_KEYUSAGE_CRLSIGN },
1431 
1432 	/* Access information */
1433 	{ CRYPT_ATTRIBUTE_CURRENT, IS_NUMERIC, CRYPT_CERTINFO_AUTHORITYINFO_RTCS },
1434 	{ CRYPT_CERTINFO_UNIFORMRESOURCEIDENTIFIER, IS_STRING, 0, "http://localhost" },
1435 
1436 	{ CRYPT_ATTRIBUTE_NONE, IS_VOID }
1437 	};
1438 
createCACert(const CRYPT_DEVICE cryptDevice)1439 static int createCACert( const CRYPT_DEVICE cryptDevice )
1440 	{
1441 	CRYPT_CONTEXT cryptContext;
1442 	CRYPT_CERTIFICATE cryptCert;
1443 	int status;
1444 
1445 	/* Generate a key in the device */
1446 	printf( "Generating a CA key in the device..." );
1447 	status = cryptDeviceCreateContext( cryptDevice, &cryptContext,
1448 						( SERVER_DEVICE_TYPE == CRYPT_DEVICE_FORTEZZA ) ? \
1449 							CRYPT_ALGO_DSA : CRYPT_ALGO_RSA );
1450 	if( cryptStatusError( status ) )
1451 		{
1452 		printf( "\ncryptDeviceCreateContext() failed with error code %d, "
1453 				"line %d.\n", status, __LINE__ );
1454 		return( FALSE );
1455 		}
1456 	status = cryptSetAttributeString( cryptContext, CRYPT_CTXINFO_LABEL,
1457 									  "CA key", strlen( "CA key" ) );
1458 	if( cryptStatusOK( status ) )
1459 		status = cryptGenerateKey( cryptContext );
1460 	if( cryptStatusError( status ) )
1461 		{
1462 		cryptDestroyContext( cryptContext );
1463 		printf( "\ncryptGenerateKey() failed with error code %d, line %d.\n",
1464 				status, __LINE__ );
1465 		return( FALSE );
1466 		}
1467 	puts( " done." );
1468 
1469 	/* Create a certificate for the key */
1470 	printf( "Generating a CA certificate for the key..." );
1471 	status = cryptCreateCert( &cryptCert, CRYPT_UNUSED,
1472 							  CRYPT_CERTTYPE_CERTIFICATE );
1473 	if( cryptStatusError( status ) )
1474 		return( FALSE );
1475 	status = cryptSetAttribute( cryptCert,
1476 						CRYPT_CERTINFO_SUBJECTPUBLICKEYINFO, cryptContext );
1477 	if( cryptStatusOK( status ) && \
1478 		!addCertFields( cryptCert, rootCACertData, __LINE__ ) )
1479 		return( FALSE );
1480 	if( cryptStatusOK( status ) )
1481 		status = cryptSignCert( cryptCert, cryptContext );
1482 	cryptDestroyContext( cryptContext );
1483 	if( cryptStatusError( status ) )
1484 		{
1485 		cryptDestroyCert( cryptCert );
1486 		printf( "\nCreation of certificate failed with error code %d, "
1487 				"line %d.\n", status, __LINE__ );
1488 		return( FALSE );
1489 		}
1490 	puts( " done." );
1491 
1492 	/* Update the key with the CA certificate */
1493 	printf( "Updating device with certificate..." );
1494 	status = cryptAddPublicKey( cryptDevice, cryptCert );
1495 	cryptDestroyCert( cryptCert );
1496 	if( cryptStatusError( status ) )
1497 		{
1498 		printf( "\ncryptAddPublicKey() failed with error code %d, line %d.\n",
1499 				status, __LINE__ );
1500 		return( FALSE );
1501 		}
1502 	puts( " done." );
1503 
1504 	return( TRUE );
1505 	}
1506 
1507 /* Connect to a device */
1508 
connectDevice(CRYPT_DEVICE * cryptDevice,CRYPT_DEVICE_TYPE type,const int slotNo)1509 static int connectDevice( CRYPT_DEVICE *cryptDevice, CRYPT_DEVICE_TYPE type,
1510 						  const int slotNo )
1511 	{
1512 	char buffer[ 128 ];
1513 	int status;
1514 
1515 	/* Clear return value */
1516 	*cryptDevice = -1;
1517 
1518 	/* Connect to the device */
1519 	if( slotNo == CRYPT_USE_DEFAULT )
1520 		{
1521 		printf( "Connecting to crypto device in default slot..." );
1522 		strcpy( buffer, "[Autodetect]" );
1523 		}
1524 	else
1525 		{
1526 		printf( "Connecting to crypto device in slot %d...", slotNo );
1527 		sprintf( buffer, "[Autodetect]::%d", slotNo );
1528 		}
1529 	status = cryptDeviceOpen( cryptDevice, CRYPT_UNUSED, type, buffer );
1530 	if( cryptStatusError( status ) )
1531 		{
1532 		if( status == CRYPT_ERROR_PARAM3 || status == CRYPT_ERROR_NOTFOUND )
1533 			puts( "\nDevice not detected, skipping test." );
1534 		else
1535 			printf( "\ncryptDeviceOpen() failed with error code %d, line "
1536 					"%d.\n", status, __LINE__ );
1537 		return( FALSE );
1538 		}
1539 	puts( " done." );
1540 
1541 	return( TRUE );
1542 	}
1543 
1544 /* Log on to a device */
1545 
logonDevice(const CRYPT_DEVICE cryptDevice,const char * userPIN)1546 static int logonDevice( const CRYPT_DEVICE cryptDevice, const char *userPIN )
1547 	{
1548 	char tokenLabel[ CRYPT_MAX_TEXTSIZE + 1 ];
1549 	int loggedOn, tokenLabelSize, status;
1550 
1551 	/* Tell the user what we're talking to */
1552 	status = cryptGetAttributeString( cryptDevice, CRYPT_DEVINFO_LABEL,
1553 									  tokenLabel, &tokenLabelSize );
1554 	if( cryptStatusError( status ) )
1555 		puts( "(Device doesn't appear to have a label)." );
1556 	else
1557 		{
1558 		tokenLabel[ tokenLabelSize ] = '\0';
1559 		printf( "Device label is '%s'.\n", tokenLabel );
1560 		}
1561 
1562 	/* See if we need to authenticate ourselves */
1563 	status = cryptGetAttribute( cryptDevice, CRYPT_DEVINFO_LOGGEDIN,
1564 								&loggedOn );
1565 	if( cryptStatusError( status ) )
1566 		{
1567 		puts( "Couldn't obtain device login status." );
1568 		return( FALSE );
1569 		}
1570 	if( loggedOn )
1571 		{
1572 		/* Device may not require a login, or has already been logged in
1573 		   via a keypad or similar mechanism */
1574 		puts( "Device is already logged in, skipping login." );
1575 		return( TRUE );
1576 		}
1577 
1578 	/* Try and log in */
1579 	printf( "Logging on to the device..." );
1580 	status = cryptSetAttributeString( cryptDevice,
1581 								CRYPT_DEVINFO_AUTHENT_USER, userPIN,
1582 								strlen( userPIN ) );
1583 	if( status == CRYPT_ERROR_INITED )
1584 		{
1585 		/* Some devices may not require any login, in which case we're
1586 		   done */
1587 		puts( " device is already logged in." );
1588 		return( TRUE );
1589 		}
1590 	if( status == CRYPT_ERROR_NOTINITED )
1591 		{
1592 		/* It's an uninitialised device, tell the user and exit */
1593 		puts( " device needs to be initialised." );
1594 		return( FALSE );
1595 		}
1596 	if( cryptStatusError( status ) )
1597 		{
1598 		printf( "\nDevice login failed with error code %d, line %d.\n",
1599 				status, __LINE__ );
1600 		return( FALSE );
1601 		}
1602 	puts( " done." );
1603 	return( TRUE );
1604 	}
1605 
1606 /* Initialise a device */
1607 
initDevice(const CRYPT_DEVICE cryptDevice,const char * defaultSSOPIN,const char * ssoPIN,const char * userPIN)1608 static int initDevice( const CRYPT_DEVICE cryptDevice,
1609 					   const char *defaultSSOPIN, const char *ssoPIN,
1610 					   const char *userPIN )
1611 	{
1612 	int status;
1613 
1614 	/* Most devices don't distinguish between zeroisation and initialisation
1615 	   so we only need to zeroise the device if it's a Fortezza card */
1616 	if( CLIENT_DEVICE_TYPE == CRYPT_DEVICE_FORTEZZA )
1617 		{
1618 		printf( "Zeroising device..." );
1619 		status = cryptSetAttributeString( cryptDevice,
1620 						CRYPT_DEVINFO_ZEROISE, FORTEZZA_ZEROISE_PIN,
1621 						strlen( FORTEZZA_ZEROISE_PIN ) );
1622 		if( cryptStatusError( status ) )
1623 			{
1624 			printf( "\nCouldn't zeroise device, status = %d, line %d.\n",
1625 					status, __LINE__ );
1626 			return( FALSE );
1627 			}
1628 		puts( " done." );
1629 		}
1630 
1631 	/* Initialise the device and set the SO PIN */
1632 	printf( "Initialising device with default SO PIN '%s'...",
1633 			defaultSSOPIN );
1634 	status = cryptSetAttributeString( cryptDevice, CRYPT_DEVINFO_INITIALISE,
1635 									  defaultSSOPIN, strlen( defaultSSOPIN ) );
1636 	if( cryptStatusError( status ) )
1637 		{
1638 		printf( "\nCouldn't initialise device, status = %d, line %d.\n",
1639 				status, __LINE__ );
1640 		return( FALSE );
1641 		}
1642 	puts( " done." );
1643 	printf( "Setting SO PIN to '%s'...", ssoPIN );
1644 	status = cryptSetAttributeString( cryptDevice,
1645 									  CRYPT_DEVINFO_SET_AUTHENT_SUPERVISOR,
1646 									  ssoPIN, strlen( ssoPIN ) );
1647 	if( cryptStatusError( status ) )
1648 		{
1649 		printf( "\nCouldn't set SO PIN, status = %d, line %d.\n", status,
1650 				__LINE__ );
1651 		return( FALSE );
1652 		}
1653 	puts( " done." );
1654 
1655 	/* If it's a Fortezza card, create a dummy PAA key and install its
1656 	   certificate.  We have to do it at this point because the operation is
1657 	   only allowed in the SSO initialised state.  In addition we can't use
1658 	   the card for this operation because certificate slot 0 is a data-only
1659 	   slot (that is, it can't correspond to a key held on the card) so we
1660 	   create a dummy external certificate and use that */
1661 	if( CLIENT_DEVICE_TYPE == CRYPT_DEVICE_FORTEZZA )
1662 		{
1663 		CRYPT_CERTIFICATE cryptCert;
1664 		CRYPT_CONTEXT signContext;
1665 
1666 		printf( "Loading PAA certificate..." );
1667 		if( !loadDSAContexts( CRYPT_UNUSED, &signContext, NULL ) )
1668 			return( FALSE );
1669 		status = cryptCreateCert( &cryptCert, CRYPT_UNUSED,
1670 								  CRYPT_CERTTYPE_CERTIFICATE );
1671 		if( cryptStatusError( status ) )
1672 			return( FALSE );
1673 		status = cryptSetAttribute( cryptCert,
1674 						CRYPT_CERTINFO_SUBJECTPUBLICKEYINFO, signContext );
1675 		if( cryptStatusOK( status ) && \
1676 			!addCertFields( cryptCert, paaCertData, __LINE__ ) )
1677 			return( FALSE );
1678 		if( cryptStatusOK( status ) )
1679 			status = cryptSignCert( cryptCert, signContext );
1680 		cryptDestroyContext( signContext );
1681 		if( cryptStatusError( status ) )
1682 			{
1683 			cryptDestroyCert( cryptCert );
1684 			printf( "\nCreation of certificate failed with error code %d, "
1685 					"line %d.\n", status, __LINE__ );
1686 			return( FALSE );
1687 			}
1688 		status = cryptAddPublicKey( cryptDevice, cryptCert );
1689 		cryptDestroyCert( cryptCert );
1690 		if( cryptStatusError( status ) )
1691 			{
1692 			printf( "\ncryptAddPublicKey() failed with error code %d, line "
1693 					"%d.\n", status, __LINE__ );
1694 			return( FALSE );
1695 			}
1696 		puts( " done." );
1697 		}
1698 
1699 	/* Set the user PIN and log on as the user.  Some devices automatically
1700 	   log the user in when they set the user password, however, for some
1701 	   devices this is a pseudo-login for which any subsequent operations
1702 	   fail with a not-logged-in error or something similar, so rather than
1703 	   relying on the existing login we always (re-)log in, which performs
1704 	   an explicit logoff if we're already logged in at the time */
1705 	printf( "Setting user PIN to '%s'...", userPIN );
1706 	status = cryptSetAttributeString( cryptDevice,
1707 									  CRYPT_DEVINFO_SET_AUTHENT_USER,
1708 									  userPIN, strlen( userPIN ) );
1709 	if( cryptStatusOK( status ) )
1710 		status = cryptSetAttributeString( cryptDevice,
1711 										  CRYPT_DEVINFO_AUTHENT_USER,
1712 										  userPIN, strlen( userPIN ) );
1713 	if( cryptStatusError( status ) )
1714 		{
1715 		printf( "\nCouldn't set user PIN/log on as user, status = %d, line "
1716 				"%d.\n", status, __LINE__ );
1717 		return( FALSE );
1718 		}
1719 	puts( " done." );
1720 
1721 	return( TRUE );
1722 	}
1723 
1724 /* Open a certificate store */
1725 
openCertStore(CRYPT_KEYSET * cryptCertStore)1726 static int openCertStore( CRYPT_KEYSET *cryptCertStore )
1727 	{
1728 	int status;
1729 
1730 	/* Clear return value */
1731 	*cryptCertStore = -1;
1732 
1733 	/* Open the certificate store */
1734 	printf( "Opening CA certificate store..." );
1735 	status = cryptKeysetOpen( cryptCertStore, CRYPT_UNUSED,
1736 							  CRYPT_KEYSET_ODBC_STORE, "testcertstore",
1737 							  CRYPT_KEYOPT_CREATE );
1738 	if( status == CRYPT_ERROR_DUPLICATE )
1739 		status = cryptKeysetOpen( cryptCertStore, CRYPT_UNUSED,
1740 								  CRYPT_KEYSET_ODBC_STORE, "testcertstore",
1741 								  CRYPT_KEYOPT_NONE );
1742 	if( cryptStatusError( status ) )
1743 		{
1744 		printf( "\ncryptKeysetOpen() failed with error code %d, line %d.\n",
1745 				status, __LINE__ );
1746 		return( FALSE );
1747 		}
1748 	puts( " done." );
1749 
1750 	return( TRUE );
1751 	}
1752 
1753 /* Add a PKI user to a certificate store */
1754 
initUserInfo(const CRYPT_KEYSET cryptCertStore,const char * userName)1755 static int initUserInfo( const CRYPT_KEYSET cryptCertStore,
1756 						 const char *userName )
1757 	{
1758 	CRYPT_CERTIFICATE cryptPKIUser;
1759 	int length, status;
1760 
1761 	/* Create the PKI user object and add the user's identification
1762 	   information */
1763 	printf( "Creating PKI user..." );
1764 	status = cryptCreateCert( &cryptPKIUser, CRYPT_UNUSED,
1765 							  CRYPT_CERTTYPE_PKIUSER );
1766 	if( cryptStatusError( status ) )
1767 		{
1768 		printf( "\ncryptCreateCert() failed with error code %d, line %d.\n",
1769 				status, __LINE__ );
1770 		return( FALSE );
1771 		}
1772 	status = cryptSetAttributeString( cryptPKIUser,
1773 									  CRYPT_CERTINFO_COMMONNAME, userName,
1774 									  strlen( userName ) );
1775 	if( cryptStatusError( status ) )
1776 		return( attrErrorExit( cryptPKIUser, "cryptSetAttributeString()",
1777 							   status, __LINE__ ) );
1778 	puts( " done." );
1779 
1780 	/* Add the user info to the certificate store */
1781 	printf( "Adding PKI user to CA certificate store..." );
1782 	status = cryptCAAddItem( cryptCertStore, cryptPKIUser );
1783 	if( status == CRYPT_ERROR_DUPLICATE )
1784 		{
1785 		char userCN[ CRYPT_MAX_TEXTSIZE + 1 ];
1786 
1787 		/* The PKI user info is already present from a previous run, get the
1788 		   existing info */
1789 		printf( "\nPKI user information is already present from a previous "
1790 				"run, re-using existing\n  PKI user data..." );
1791 		status = cryptGetAttributeString( cryptPKIUser,
1792 										  CRYPT_CERTINFO_COMMONNAME,
1793 										  userCN, &length );
1794 		if( cryptStatusError( status ) )
1795 			return( attrErrorExit( cryptPKIUser, "cryptGetAttribute()",
1796 								   status, __LINE__ ) );
1797 		userCN[ length ] = '\0';
1798 		cryptDestroyCert( cryptPKIUser );
1799 		status = cryptCAGetItem( cryptCertStore, &cryptPKIUser,
1800 								 CRYPT_CERTTYPE_PKIUSER, CRYPT_KEYID_NAME,
1801 								 userCN );
1802 		}
1803 	if( cryptStatusError( status ) )
1804 		return( extErrorExit( cryptCertStore, "cryptCAAddItem()", status,
1805 							  __LINE__ ) );
1806 	puts( " done." );
1807 
1808 	/* Display the information for the user */
1809 	if( !printCertInfo( cryptPKIUser ) )
1810 		return( FALSE );
1811 
1812 	/* Clean up */
1813 	cryptDestroyCert( cryptPKIUser );
1814 	return( TRUE );
1815 	}
1816 
1817 /* Get details for a PKI user */
1818 
getUserInfo(char * userID,char * issuePW)1819 static int getUserInfo( char *userID, char *issuePW )
1820 	{
1821 #ifndef CLIENT_ID
1822 	CRYPT_KEYSET cryptCertStore;
1823 	CRYPT_CERTIFICATE cryptPKIUser;
1824 	int length, status;
1825 
1826 	/* Get the PKIUser object from the certificate store */
1827 	status = cryptKeysetOpen( &cryptCertStore, CRYPT_UNUSED,
1828 							  CRYPT_KEYSET_ODBC_STORE, "testcertstore",
1829 							  CRYPT_KEYOPT_NONE );
1830 	if( cryptStatusError( status ) )
1831 		{
1832 		printf( "cryptKeysetOpen() failed with error code %d, line %d.\n",
1833 				status, __LINE__ );
1834 		return( FALSE );
1835 		}
1836 	status = cryptCAGetItem( cryptCertStore, &cryptPKIUser,
1837 							 CRYPT_CERTTYPE_PKIUSER, CRYPT_KEYID_NAME,
1838 							 "Test PKI user" );
1839 	cryptKeysetClose( cryptCertStore );
1840 	if( cryptStatusError( status ) )
1841 		return( extErrorExit( cryptCertStore, "cryptCAGetItem()", status,
1842 							  __LINE__ ) );
1843 
1844 	/* Extract the information from the PKIUser object */
1845 	status = cryptGetAttributeString( cryptPKIUser,
1846 									  CRYPT_CERTINFO_PKIUSER_ID,
1847 									  userID, &length );
1848 	if( cryptStatusOK( status ) )
1849 		{
1850 		userID[ length ] = '\0';
1851 		status = cryptGetAttributeString( cryptPKIUser,
1852 									CRYPT_CERTINFO_PKIUSER_ISSUEPASSWORD,
1853 									issuePW, &length );
1854 		}
1855 	if( cryptStatusOK( status ) )
1856 		issuePW[ length ] = '\0';
1857 	cryptDestroyCert( cryptPKIUser );
1858 	if( cryptStatusError( status ) )
1859 		return( attrErrorExit( cryptPKIUser, "cryptGetAttribute()", status,
1860 							   __LINE__ ) );
1861 #else
1862 	strcpy( userID, CLIENT_ID );
1863 	strcpy( issuePW, CLIENT_AUTHENTICATOR );
1864 #endif /* CLIENT_ID */
1865 
1866 	/* We've got what we need, tell the user what we're doing */
1867 	printf( "Using user name %s, password %s.\n", userID, issuePW );
1868 	return( TRUE );
1869 	}
1870 
1871 /* Run the PnP PKI server */
1872 
pnpServer(const CRYPT_DEVICE cryptDevice,const CRYPT_KEYSET cryptCertStore)1873 static int pnpServer( const CRYPT_DEVICE cryptDevice,
1874 					  const CRYPT_KEYSET cryptCertStore )
1875 	{
1876 	CRYPT_SESSION cryptSession;
1877 	CRYPT_CONTEXT cryptPrivateKey;
1878 	int caCertTrusted, status;
1879 
1880 	/* Perform a cleanup action to remove any leftover requests from
1881 	   previous runs */
1882 	status = cryptCACertManagement( NULL, CRYPT_CERTACTION_CLEANUP,
1883 									cryptCertStore, CRYPT_UNUSED,
1884 									CRYPT_UNUSED );
1885 	if( cryptStatusError( status ) )
1886 		{
1887 		printf( "\nCA certificate store cleanup failed with error code %d, "
1888 				"line %d.\n", status, __LINE__ );
1889 		return( FALSE );
1890 		}
1891 
1892 	/* Get the CA's key from the device and make it trusted for PKIBoot
1893 	   functionality.  If we're running the test in loopback mode with the
1894 	   Fortezza interface we can't have both the client and server using
1895 	   Fortezza cards due to Spyrus driver bugs, and also can't have the
1896 	   client and server as PKCS #11 and Fortezza due to other driver bugs,
1897 	   so we have to fake the CA key using a software-only implementation */
1898 	printf( "Making CA certificate trusted for PKIBoot..." );
1899 #ifndef CLIENT_ID
1900 	if( CLIENT_DEVICE_TYPE == CRYPT_DEVICE_FORTEZZA )
1901 		status = getPrivateKey( &cryptPrivateKey, CA_PRIVKEY_FILE,
1902 								CA_PRIVKEY_LABEL, TEST_PRIVKEY_PASSWORD );
1903 	else
1904 #endif /* CLIENT_ID */
1905 		status = cryptGetPrivateKey( cryptDevice, &cryptPrivateKey,
1906 									 CRYPT_KEYID_NAME, "CA key", NULL );
1907 	if( cryptStatusError( status ) )
1908 		{
1909 		printf( "\nCA private key read failed with error code %d, "
1910 				"line %d.\n", status, __LINE__ );
1911 		return( FALSE );
1912 		}
1913 	cryptGetAttribute( cryptPrivateKey, CRYPT_CERTINFO_TRUSTED_IMPLICIT,
1914 					   &caCertTrusted );
1915 	cryptSetAttribute( cryptPrivateKey, CRYPT_CERTINFO_TRUSTED_IMPLICIT, 1 );
1916 	puts( " done." );
1917 
1918 	/* Create the CMP session and add the CA key and certificate store */
1919 	printf( "Creating CMP server session..." );
1920 	status = cryptCreateSession( &cryptSession, CRYPT_UNUSED,
1921 								 CRYPT_SESSION_CMP_SERVER );
1922 	if( cryptStatusError( status ) )
1923 		{
1924 		printf( "\ncryptCreateSession() failed with error code %d, line "
1925 				"%d.\n", status, __LINE__ );
1926 		return( FALSE );
1927 		}
1928 	status = cryptSetAttribute( cryptSession,
1929 							CRYPT_SESSINFO_PRIVATEKEY, cryptPrivateKey );
1930 	if( cryptStatusOK( status ) )
1931 		status = cryptSetAttribute( cryptSession,
1932 							CRYPT_SESSINFO_KEYSET, cryptCertStore );
1933 	if( cryptStatusError( status ) )
1934 		return( attrErrorExit( cryptSession, "cryptSetAttribute()",
1935 							   status, __LINE__ ) );
1936 	if( !setConnectInfo( cryptSession, SERVER_MACHINE_ADDRESS,
1937 						 SERVER_MACHINE_PORT, NET_TIMEOUT ) )
1938 		return( FALSE );
1939 	puts( " done." );
1940 
1941 	/* Activate the session */
1942 	status = activatePersistentServerSession( cryptSession, TRUE );
1943 	if( cryptStatusError( status ) )
1944 		return( extErrorExit( cryptSession, "Attempt to activate CMP "
1945 							  "server session", status, __LINE__ ) );
1946 
1947 	/* Clean up */
1948 	cryptDestroySession( cryptSession );
1949 	if( !caCertTrusted )
1950 		cryptSetAttribute( cryptPrivateKey,
1951 						   CRYPT_CERTINFO_TRUSTED_IMPLICIT, 0 );
1952 
1953 	return( TRUE );
1954 	}
1955 
1956 /* Run the PnP PKI client */
1957 
pnpClient(const CRYPT_DEVICE cryptDevice,const char * userID,const char * issuePW)1958 static int pnpClient( const CRYPT_DEVICE cryptDevice, const char *userID,
1959 					  const char *issuePW )
1960 	{
1961 	CRYPT_SESSION cryptSession;
1962 	int status;
1963 
1964 	/* Create the CMP session and set up the information we need for the
1965 	   plug-and-play PKI process */
1966 	printf( "Creating CMP client session..." );
1967 	status = cryptCreateSession( &cryptSession, CRYPT_UNUSED,
1968 								 CRYPT_SESSION_CMP );
1969 	if( cryptStatusError( status ) )
1970 		{
1971 		printf( "\ncryptCreateSession() failed with error code %d, line "
1972 				"%d.\n", status, __LINE__ );
1973 		return( FALSE );
1974 		}
1975 	status = cryptSetAttributeString( cryptSession,
1976 									  CRYPT_SESSINFO_USERNAME, userID,
1977 									  paramStrlen( userID ) );
1978 	if( cryptStatusOK( status ) )
1979 		status = cryptSetAttributeString( cryptSession,
1980 										  CRYPT_SESSINFO_PASSWORD,
1981 										  issuePW, paramStrlen( issuePW ) );
1982 	if( cryptStatusOK( status ) )
1983 		status = cryptSetAttribute( cryptSession,
1984 									CRYPT_SESSINFO_CMP_PRIVKEYSET,
1985 									cryptDevice );
1986 	if( cryptStatusError( status ) )
1987 		{
1988 		printf( "\nAddition of session information failed with error code "
1989 				"%d, line %d.\n", status, __LINE__ );
1990 		return( FALSE );
1991 		}
1992 	if( !setConnectInfo( cryptSession, SERVER_MACHINE_ADDRESS,
1993 						 SERVER_MACHINE_PORT, NET_TIMEOUT ) )
1994 		return( FALSE );
1995 	puts( " done." );
1996 
1997 	/* Activate the session */
1998 	printf( "Obtaining keys and certs..." );
1999 	status = cryptSetAttribute( cryptSession, CRYPT_SESSINFO_ACTIVE, TRUE );
2000 	if( cryptStatusError( status ) )
2001 		{
2002 		printExtError( cryptSession, "\nAttempt to activate plug-and-play "
2003 					   "PKI client session", status, __LINE__ );
2004 		cryptDestroySession( cryptSession );
2005 		return( FALSE );
2006 		}
2007 	puts( " done." );
2008 
2009 	/* Clean up */
2010 	cryptDestroySession( cryptSession );
2011 	return( TRUE );
2012 	}
2013 
2014 /* Client/server test harness */
2015 
testServer(void)2016 static int testServer( void )
2017 	{
2018 	CRYPT_KEYSET cryptCertStore;
2019 	CRYPT_DEVICE cryptDevice;
2020 	int status;
2021 
2022 	/* Open the device and certificate store */
2023 	status = connectDevice( &cryptDevice, SERVER_DEVICE_TYPE, 0 );
2024 	if( status )
2025 		status = openCertStore( &cryptCertStore );
2026 	if( !status )
2027 		return( FALSE );
2028 
2029 	/* Create a CA key in the device.  Due to Spyrus bugs it's necessary to
2030 	   disconnect from the device and then re-connect after initialising it
2031 	   or crypto operations fail in various ways.  In older (and even
2032 	   buggier) devices crypto ops simply fail after initialisation and it
2033 	   may be necessary to eject and re-insert the card before they'll work
2034 	   properly */
2035 #if 0
2036 	status = initDevice( cryptDevice, DEFAULT_SSO_PIN, SSO_PIN, USER_PIN );
2037 	cryptDeviceClose( cryptDevice );
2038 	if( status )
2039 		status = connectDevice( &cryptDevice, SERVER_DEVICE_TYPE, 0 );
2040 	if( status )
2041 		status = logonDevice( cryptDevice, USER_PIN );
2042 	if( status )
2043 		status = createCACert( cryptDevice );
2044 #else
2045 	status = logonDevice( cryptDevice, USER_PIN );
2046 #endif /* 0 */
2047 	if( !status )
2048 		return( FALSE );
2049 
2050 	/* Init the PKI user */
2051 	status = initUserInfo( cryptCertStore, "Test user #1" );
2052 	if( !status )
2053 		return( FALSE );
2054 
2055 	/* Run the PnP PKI server */
2056 	status = pnpServer( cryptDevice, cryptCertStore );
2057 
2058 	/* Clean up */
2059 	cryptDeviceClose( cryptDevice );
2060 	cryptKeysetClose( cryptCertStore );
2061 
2062 	return( status );
2063 	}
2064 
testClient(void)2065 static int testClient( void )
2066 	{
2067 	CRYPT_DEVICE cryptDevice;
2068 	char userID[ CRYPT_MAX_TEXTSIZE + 1 ], issuePW[ CRYPT_MAX_TEXTSIZE + 1 ];
2069 	int status;
2070 
2071 	/* Open the device and get the user ID and password from the certificate
2072 	   store.  Normally this would be communicated directly, for our test
2073 	   purposes we cheat and get it from the certificate store */
2074 	status = connectDevice( &cryptDevice, CLIENT_DEVICE_TYPE,
2075 							CLIENT_TOKEN_SLOT );
2076 	if( status )
2077 		status = getUserInfo( userID, issuePW );
2078 	if( !status )
2079 		return( FALSE );
2080 
2081 	/* Initialise the device */
2082 #if 1
2083 	status = initDevice( cryptDevice, DEFAULT_SSO_PIN, SSO_PIN, USER_PIN );
2084 	cryptDeviceClose( cryptDevice );
2085 	if( status )
2086 		status = connectDevice( &cryptDevice, CLIENT_DEVICE_TYPE,
2087 								CLIENT_TOKEN_SLOT );
2088 	if( status )
2089 		status = logonDevice( cryptDevice, USER_PIN );
2090 #else
2091 	status = logonDevice( cryptDevice, USER_PIN );
2092 #endif /* 0 */
2093 	if( !status )
2094 		return( FALSE );
2095 
2096 	/* Run the PnP PKI client */
2097 	status = pnpClient( cryptDevice, userID, issuePW );
2098 
2099 	/* Clean up */
2100 	cryptDeviceClose( cryptDevice );
2101 
2102 	return( status );
2103 	}
2104 
2105 /* Perform a client/server loopback test */
2106 
2107 #ifdef WINDOWS_THREADS
2108 
serverThread(void * dummy)2109 unsigned __stdcall serverThread( void *dummy )
2110 	{
2111 	testServer();
2112 	_endthreadex( 0 );
2113 	return( 0 );
2114 	}
2115 
testDeviceLifeCycle(void)2116 int testDeviceLifeCycle( void )
2117 	{
2118 #ifdef CLIENT_ID
2119 #if 1
2120 	return( testClient() );
2121 #else
2122 	return( testServer() );
2123 #endif /* 0 */
2124 #else
2125 	HANDLE hThread;
2126 	unsigned threadID;
2127 	int status;
2128 
2129 	/* Start the server and wait 15s for it to initialise */
2130 	hThread = ( HANDLE ) _beginthreadex( NULL, 0, serverThread,
2131 										 NULL, 0, &threadID );
2132 	Sleep( 15000 );
2133 
2134 	/* Connect to the local server with PKIBoot enabled */
2135 	status = testClient();
2136 	if( WaitForSingleObject( hThread, 15000 ) == WAIT_TIMEOUT )
2137 		{
2138 		puts( "Warning: Server thread is still active due to session "
2139 			  "negotiation failure,\n         this will cause an error "
2140 			  "condition when cryptEnd() is called due\n         to "
2141 			  "resources remaining allocated.  Press a key to continue." );
2142 		getchar();
2143 		}
2144 	CloseHandle( hThread );
2145 
2146 	return( status );
2147 #endif /* CLIENT_ID */
2148 	}
2149 #endif /* WINDOWS_THREADS */
2150 #endif /* WinCE */
2151 
2152 #endif /* TEST_DEVICE */
2153 
2154 /****************************************************************************
2155 *																			*
2156 *							User Management Routines Test					*
2157 *																			*
2158 ****************************************************************************/
2159 
2160 #ifdef TEST_USER
2161 
testUser(void)2162 int testUser( void )
2163 	{
2164 	CRYPT_USER cryptUser;
2165 	int status;
2166 
2167 	puts( "Testing (minimal) user management functions..." );
2168 
2169 	/* Perform a zeroise.  This currently isn't done because (a) it would
2170 	   zeroise all user data whenever anyone runs the self-test and (b) the
2171 	   external API to trigger this isn't defined yet */
2172 /*	status = cryptZeroise( ... ); */
2173 
2174 	/* Log in as primary SO using the zeroisation password.  Because of the
2175 	   above situation this currently performs an implicit zeroise */
2176 	status = cryptLogin( &cryptUser, TEXT( "Security officer" ),
2177 						 TEXT( "zeroised" ) );
2178 	if( cryptStatusError( status ) )
2179 		{
2180 		printf( "cryptLogin() (Primary SO) failed with error code %d, line "
2181 				"%d.\n", status, __LINE__ );
2182 		return( FALSE );
2183 		}
2184 
2185 	/* Set the SO password */
2186 	status = cryptSetAttributeString( cryptUser, CRYPT_USERINFO_PASSWORD,
2187 									  TEST_PASSWORD, paramStrlen( TEST_PASSWORD ) );
2188 	if( cryptStatusError( status ) )
2189 		{
2190 		printf( "cryptSetAttributeString() failed with error code %d, "
2191 				"line %d.\n", status, __LINE__ );
2192 		return( FALSE );
2193 		}
2194 
2195 	/* Log out and log in again with the new password.  At the moment it's
2196 	   possible to use any password until the PKCS #15 attribute situation
2197 	   is resolved */
2198 	status = cryptLogout( cryptUser );
2199 	if( cryptStatusError( status ) )
2200 		{
2201 		printf( "cryptLogout() failed with error code %d, line %d.\n",
2202 				status, __LINE__ );
2203 		return( FALSE );
2204 		}
2205 	status = cryptLogin( &cryptUser, TEXT( "Security officer" ),
2206 						 TEST_PASSWORD );
2207 	if( cryptStatusError( status ) )
2208 		{
2209 		printf( "cryptLogin() (SO) failed with error code %d, line %d.\n",
2210 				status, __LINE__ );
2211 		return( FALSE );
2212 		}
2213 
2214 	/* Clean up */
2215 	cryptLogout( cryptUser );
2216 	puts( "User management tests succeeded.\n" );
2217 	return( TRUE );
2218 	}
2219 
2220 #endif /* TEST_USER */
2221