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