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