cryptlib  3.4.1
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Macros
highlvl.c
Go to the documentation of this file.
1 /****************************************************************************
2 * *
3 * cryptlib Mid and High-Level Test Routines *
4 * Copyright Peter Gutmann 1995-2005 *
5 * *
6 ****************************************************************************/
7 
8 #include <limits.h> /* To determine max.buffer size we can encrypt */
9 #include "cryptlib.h"
10 #include "test/test.h"
11 #include "misc/config.h" /* For checking availability of test options */
12 
13 #if defined( __MVS__ ) || defined( __VMCMS__ )
14  /* Suspend conversion of literals to ASCII. */
15  #pragma convlit( suspend )
16 #endif /* IBM big iron */
17 #if defined( __ILEC400__ )
18  #pragma convert( 0 )
19 #endif /* IBM medium iron */
20 
21 #ifndef max /* Some compilers don't define this */
22  #define max( a, b ) ( ( ( a ) > ( b ) ) ? ( ( int ) a ) : ( ( int ) b ) )
23 #endif /* !max */
24 
25 /****************************************************************************
26 * *
27 * Utility Functions *
28 * *
29 ****************************************************************************/
30 
31 #if defined( TEST_MIDLEVEL ) || defined( TEST_HIGHLEVEL )
32 
33 /* Test whether two session keys are identical */
34 
35 static int compareSessionKeys( const CRYPT_CONTEXT cryptContext1,
36  const CRYPT_CONTEXT cryptContext2 )
37  {
39  int blockSize, ivSize, status;
40 
41  cryptGetAttribute( cryptContext1, CRYPT_CTXINFO_BLOCKSIZE, &blockSize );
42  cryptGetAttribute( cryptContext1, CRYPT_CTXINFO_IVSIZE, &ivSize );
44  "\x00\x00\x00\x00\x00\x00\x00\x00"
45  "\x00\x00\x00\x00\x00\x00\x00\x00", ivSize );
47  "\x00\x00\x00\x00\x00\x00\x00\x00"
48  "\x00\x00\x00\x00\x00\x00\x00\x00", ivSize );
49  memcpy( buffer, "0123456789ABCDEF", max( blockSize, 8 ) );
50  status = cryptEncrypt( cryptContext1, buffer, max( blockSize, 8 ) );
51  if( cryptStatusError( status ) )
52  {
53  printf( "cryptEncrypt() with first key failed with error "
54  "code %d, line %d.\n", status, __LINE__ );
55  return( FALSE );
56  }
57  status = cryptDecrypt( cryptContext2, buffer, max( blockSize, 8 ) );
58  if( cryptStatusError( status ) )
59  {
60  printf( "cryptDecrypt() with second key failed with error "
61  "code %d, line %d.\n", status, __LINE__ );
62  return( FALSE );
63  }
64  if( memcmp( buffer, "012345678ABCDEF", max( blockSize, 8 ) ) )
65  {
66  puts( "Data decrypted with key2 != plaintext encrypted with key1." );
67  return( FALSE );
68  }
69  return( TRUE );
70  }
71 
72 #endif /* TEST_MIDLEVEL || TEST_HIGHLEVEL */
73 
74 /****************************************************************************
75 * *
76 * Mid-level Routines Test *
77 * *
78 ****************************************************************************/
79 
80 #ifdef TEST_MIDLEVEL
81 
82 /* General-purpose routines to perform a key exchange and sign and sig
83  check data */
84 
85 static int signData( const char *algoName, const CRYPT_ALGO_TYPE algorithm,
86  const CRYPT_CONTEXT externalSignContext,
87  const CRYPT_CONTEXT externalCheckContext,
88  const BOOLEAN useSidechannelProtection,
89  const BOOLEAN useSHA2,
91  {
93  CRYPT_CONTEXT signContext, checkContext;
95  const int extraData = ( formatType == CRYPT_FORMAT_CMS || \
96  formatType == CRYPT_FORMAT_SMIME ) ? \
98  BYTE buffer[ 1024 ], hashBuffer[] = "abcdefghijklmnopqrstuvwxyz";
99  int status, value, length;
100 
101  printf( "Testing %s%s digital signature%s...\n",
102  ( formatType == CRYPT_FORMAT_PGP ) ? "PGP " : "", algoName,
103  useSidechannelProtection ? " with side-channel protection" : "" );
104 
105  /* Create an SHA/SHA2 hash context and hash the test buffer. We don't
106  complete the hashing if it's a PGP signature since this hashes in
107  extra data before generating the signature */
108  status = cryptCreateContext( &hashContext, CRYPT_UNUSED,
109  useSHA2 ? CRYPT_ALGO_SHA2 : CRYPT_ALGO_SHA );
110  if( cryptStatusError( status ) )
111  return( FALSE );
112  cryptEncrypt( hashContext, hashBuffer, 26 );
113  if( formatType != CRYPT_FORMAT_PGP )
114  cryptEncrypt( hashContext, hashBuffer, 0 );
115 
116  /* Create the appropriate en/decryption contexts */
117  if( externalSignContext != CRYPT_UNUSED )
118  {
119  signContext = externalSignContext;
120  checkContext = externalCheckContext;
121  }
122  else
123  {
124  switch( algorithm )
125  {
126  case CRYPT_ALGO_RSA:
127  if( useSHA2 )
128  {
129  /* If we're using SHA-2 then we have to use a larger RSA
130  key to ensure that the hash values fits into the
131  signature data */
132  status = loadRSAContextsLarge( CRYPT_UNUSED, &checkContext,
133  &signContext );
134  }
135  else
136  {
137  status = loadRSAContexts( CRYPT_UNUSED, &checkContext,
138  &signContext );
139  }
140  break;
141 
142  case CRYPT_ALGO_DSA:
143  status = loadDSAContexts( CRYPT_UNUSED, &signContext,
144  &checkContext );
145  break;
146 
147  case CRYPT_ALGO_ECDSA:
148  status = loadECDSAContexts( &signContext, &checkContext );
149  break;
150 
151  default:
152  status = FALSE;
153  }
154  if( !status )
155  return( FALSE );
156  }
157 
158  /* Find out how big the signature will be */
159  status = cryptCreateSignatureEx( NULL, 0, &length, formatType,
160  signContext, hashContext, extraData );
161  if( cryptStatusError( status ) )
162  {
163  printf( "cryptCreateSignature() failed with error code %d, line %d.\n",
164  status, __LINE__ );
165  return( FALSE );
166  }
167  printf( "cryptCreateSignature() reports signature object will be %d "
168  "bytes long\n", length );
169  assert( length <= 1024 );
170 
171  /* Sign the hashed data */
172  if( useSidechannelProtection )
173  {
178  }
179  status = cryptCreateSignatureEx( buffer, 1024, &length, formatType,
180  signContext, hashContext, extraData );
181  if( cryptStatusError( status ) )
182  {
183  printf( "cryptCreateSignature() failed with error code %d, line %d.\n",
184  status, __LINE__ );
185  return( FALSE );
186  }
187  if( useSidechannelProtection && value != 1 )
188  {
191  }
192 
193  /* Query the signed object */
194  status = cryptQueryObject( buffer, length, &cryptObjectInfo );
195  if( cryptStatusError( status ) )
196  {
197  printf( "cryptQueryObject() failed with error code %d, line %d.\n",
198  status, __LINE__ );
199  return( FALSE );
200  }
201  printf( "cryptQueryObject() reports object type %d, algorithm %d, "
202  "hash algorithm %d.\n", cryptObjectInfo.objectType,
203  cryptObjectInfo.cryptAlgo, cryptObjectInfo.hashAlgo );
204  memset( &cryptObjectInfo, 0, sizeof( CRYPT_OBJECT_INFO ) );
205  if( formatType == CRYPT_FORMAT_CRYPTLIB )
206  {
207  debugDump( ( algorithm == CRYPT_ALGO_DSA ) ? "sigd" : \
208  ( algorithm == CRYPT_ALGO_ECDSA ) ? "sigec" : \
209  useSHA2 ? "sigr2" : "sigr", buffer, length );
210  }
211  else
212  {
213  debugDump( ( algorithm == CRYPT_ALGO_RSA ) ? \
214  "sigr.pgp" : "sigd.pgp", buffer, length );
215  }
216 
217  /* Check the signature on the hash. We have to redo the hashing for PGP
218  signatures since PGP hashes in extra odds and ends after the data has
219  been hashed */
220  if( formatType == CRYPT_FORMAT_PGP )
221  {
223  cryptEncrypt( hashContext, hashBuffer, 26 );
224  }
225  status = cryptCheckSignature( buffer, length, checkContext, hashContext );
226  if( cryptStatusError( status ) )
227  {
228  printf( "cryptCheckSignature() failed with error code %d, line %d.\n",
229  status, __LINE__ );
230  return( FALSE );
231  }
232 
233  /* Clean up */
234  cryptDestroyContext( hashContext );
235  if( externalSignContext == CRYPT_UNUSED )
236  destroyContexts( CRYPT_UNUSED, checkContext, signContext );
237  printf( "Generation and checking of %s digital signature succeeded.\n\n",
238  algoName );
239  return( TRUE );
240  }
241 
242 static int keyExportImport( const char *algoName,
243  const CRYPT_ALGO_TYPE algorithm,
244  const CRYPT_CONTEXT externalCryptContext,
245  const CRYPT_CONTEXT externalDecryptContext,
246  const CRYPT_FORMAT_TYPE formatType )
247  {
248  const CRYPT_ALGO_TYPE cryptAlgo = ( formatType == CRYPT_FORMAT_PGP ) ? \
251  CRYPT_CONTEXT cryptContext, decryptContext;
252  CRYPT_CONTEXT sessionKeyContext1, sessionKeyContext2;
253  BYTE *buffer;
254  int status, length;
255 
256  printf( "Testing %s%s public-key export/import...\n",
257  ( formatType == CRYPT_FORMAT_PGP ) ? "PGP " : "", algoName );
258 
259  /* Create encryption contexts for the session key. PGP stores the
260  session key information with the encrypted key data, so we can't
261  create the context at this point */
262  status = cryptCreateContext( &sessionKeyContext1, CRYPT_UNUSED,
263  selectCipher( cryptAlgo ) );
264  if( cryptStatusError( status ) )
265  return( FALSE );
266  cryptSetAttribute( sessionKeyContext1, CRYPT_CTXINFO_MODE,
267  ( formatType == CRYPT_FORMAT_PGP ) ? \
269  status = cryptGenerateKey( sessionKeyContext1 );
270  if( cryptStatusError( status ) )
271  return( FALSE );
272  if( formatType != CRYPT_FORMAT_PGP )
273  {
274  status = cryptCreateContext( &sessionKeyContext2, CRYPT_UNUSED,
275  selectCipher( cryptAlgo ) );
276  if( cryptStatusError( status ) )
277  return( FALSE );
278  cryptSetAttribute( sessionKeyContext2, CRYPT_CTXINFO_MODE,
279  CRYPT_MODE_OFB );
280  }
281 
282  /* Create the appropriate en/decryption contexts */
283  if( externalCryptContext != CRYPT_UNUSED )
284  {
285  cryptContext = externalCryptContext;
286  decryptContext = externalDecryptContext;
287  }
288  else
289  {
290  if( algorithm == CRYPT_ALGO_ELGAMAL )
291  status = loadElgamalContexts( &cryptContext, &decryptContext );
292  else
293  status = loadRSAContexts( CRYPT_UNUSED, &cryptContext, &decryptContext );
294  if( !status )
295  return( FALSE );
296  }
297 
298  /* Find out how big the exported key will be */
299  status = cryptExportKeyEx( NULL, 0, &length, formatType, cryptContext,
300  sessionKeyContext1 );
301  if( cryptStatusError( status ) )
302  {
303  printf( "cryptExportKeyEx() failed with error code %d, line %d.\n",
304  status, __LINE__ );
305  return( FALSE );
306  }
307  printf( "cryptExportKeyEx() reports exported key object will be %d "
308  "bytes long\n", length );
309  if( ( buffer = malloc( length ) ) == NULL )
310  return( FALSE );
311 
312  /* Export the session key */
313  status = cryptExportKeyEx( buffer, length, &length, formatType,
314  cryptContext, sessionKeyContext1 );
315  if( cryptStatusError( status ) )
316  {
317  printf( "cryptExportKeyEx() failed with error code %d, line %d.\n",
318  status, __LINE__ );
319  free( buffer );
320  return( FALSE );
321  }
322 
323  /* Query the encrypted key object */
324  status = cryptQueryObject( buffer, length, &cryptObjectInfo );
325  if( cryptStatusError( status ) )
326  {
327  printf( "cryptQueryObject() failed with error code %d, line %d.\n",
328  status, __LINE__ );
329  free( buffer );
330  return( FALSE );
331  }
332  printf( "cryptQueryObject() reports object type %d, algorithm %d.\n",
333  cryptObjectInfo.objectType, cryptObjectInfo.cryptAlgo );
334  memset( &cryptObjectInfo, 0, sizeof( CRYPT_OBJECT_INFO ) );
335  if( formatType == CRYPT_FORMAT_CRYPTLIB )
336  debugDump( ( algorithm == CRYPT_ALGO_RSA ) ? \
337  "keytrans" : "keytr_el", buffer, length );
338  else
339  debugDump( ( algorithm == CRYPT_ALGO_RSA ) ? \
340  "keytrans.pgp" : "keytr_el.pgp", buffer, length );
341 
342  /* Recreate the session key by importing the encrypted key */
343  if( formatType == CRYPT_FORMAT_PGP )
344  status = cryptImportKeyEx( buffer, length, decryptContext,
345  CRYPT_UNUSED, &sessionKeyContext2 );
346  else
347  status = cryptImportKeyEx( buffer, length, decryptContext,
348  sessionKeyContext2, NULL );
349  if( cryptStatusError( status ) )
350  {
351  printf( "cryptImportKeyEx() failed with error code %d, line %d.\n",
352  status, __LINE__ );
353  free( buffer );
354  return( FALSE );
355  }
356 
357  /* Make sure that the two keys match */
358  if( !compareSessionKeys( sessionKeyContext1, sessionKeyContext2 ) )
359  return( FALSE );
360 
361  /* Clean up */
362  destroyContexts( CRYPT_UNUSED, sessionKeyContext1, sessionKeyContext2 );
363  if( externalCryptContext == CRYPT_UNUSED )
364  destroyContexts( CRYPT_UNUSED, cryptContext, decryptContext );
365  printf( "Export/import of session key via %d-bit %s-encrypted data "
366  "block\n succeeded.\n\n", PKC_KEYSIZE, algoName );
367  free( buffer );
368  return( TRUE );
369  }
370 
371 /* Test the ability to encrypt a large amount of data */
372 
373 int testLargeBufferEncrypt( void )
374  {
376  BYTE *buffer;
377  const size_t length = ( INT_MAX <= 32768L ) ? 16384 : 1048576;
378  int i, status;
379 
380  puts( "Testing encryption of large data quantity..." );
381 
382  /* Allocate a large buffer and fill it with a known value */
383  if( ( buffer = malloc( length ) ) == NULL )
384  {
385  printf( "Couldn't allocate buffer of %ld bytes, skipping large "
386  "buffer encryption test.\n", ( long ) length );
387  return( TRUE );
388  }
389  memset( buffer, '*', length );
390 
391  /* Encrypt the buffer */
392  status = cryptCreateContext( &cryptContext, CRYPT_UNUSED, CRYPT_ALGO_DES );
393  if( cryptStatusError( status ) )
394  {
395  free( buffer );
396  return( FALSE );
397  }
398  cryptSetAttributeString( cryptContext, CRYPT_CTXINFO_KEY, "12345678", 8 );
400  "\x00\x00\x00\x00\x00\x00\x00\x00", 8 );
401  status = cryptEncrypt( cryptContext, buffer, length );
402  if( cryptStatusError( status ) )
403  {
404  printf( "cryptEncrypt() of large data quantity failed with error "
405  "code %d, line %d.\n", status, __LINE__ );
406  free( buffer );
407  return( FALSE );
408  }
409  cryptDestroyContext( cryptContext );
410 
411  /* Decrypt the buffer */
412  status = cryptCreateContext( &cryptContext, CRYPT_UNUSED, CRYPT_ALGO_DES );
413  if( cryptStatusError( status ) )
414  {
415  free( buffer );
416  return( FALSE );
417  }
418  cryptSetAttributeString( cryptContext, CRYPT_CTXINFO_KEY, "12345678", 8 );
420  "\x00\x00\x00\x00\x00\x00\x00\x00", 8 );
421  status = cryptDecrypt( cryptContext, buffer, length );
422  if( cryptStatusError( status ) )
423  {
424  printf( "cryptDecrypt() of large data quantity failed with error "
425  "code %d, line %d.\n", status, __LINE__ );
426  free( buffer );
427  return( FALSE );
428  }
429  cryptDestroyContext( cryptContext );
430 
431  /* Make sure that it went OK */
432  for( i = 0; i < ( int ) length; i++ )
433  {
434  if( buffer[ i ] != '*' )
435  {
436  printf( "Decrypted data != original plaintext at position %d, "
437  "line %d.\n", i, __LINE__ );
438  free( buffer );
439  return( FALSE );
440  }
441  }
442 
443  /* Clean up */
444  free( buffer );
445  printf( "Encryption of %ld bytes of data succeeded.\n\n",
446  ( long ) length );
447  return( TRUE );
448  }
449 
450 /* Test the code to derive a fixed-length encryption key from a variable-
451  length user key */
452 
453 static int deriveKey( const C_STR userKey, const int userKeyLength,
454  BOOLEAN useAltAlgo )
455  {
456  CRYPT_CONTEXT cryptContext, decryptContext;
457  int status;
458 
459  /* Create IDEA/CBC encryption and decryption contexts and load them with
460  identical salt values for the key derivation (this is easier than
461  reading the salt from one and writing it to the other) */
462  status = cryptCreateContext( &cryptContext, CRYPT_UNUSED,
464  if( cryptStatusOK( status ) )
465  status = cryptCreateContext( &decryptContext, CRYPT_UNUSED,
467  if( cryptStatusError( status ) )
468  return( FALSE );
470  "\x12\x34\x56\x78\x78\x56\x34\x12", 8 );
472  "\x12\x34\x56\x78\x78\x56\x34\x12", 8 );
473  if( useAltAlgo )
474  {
479  }
480 
481  /* Load an IDEA key derived from a user key into both contexts */
482  status = cryptSetAttributeString( cryptContext,
484  userKey, userKeyLength );
485  if( cryptStatusError( status ) )
486  {
487  printf( "Key derivation failed with error code %d, line %d.\n",
488  status, __LINE__ );
489  return( FALSE );
490  }
491  status = cryptSetAttributeString( decryptContext,
493  userKey, userKeyLength );
494  if( cryptStatusError( status ) )
495  {
496  printf( "Key derivation failed with error code %d, line %d.\n",
497  status, __LINE__ );
498  return( FALSE );
499  }
500 
501  /* Make sure that the two derived keys match */
502  if( !compareSessionKeys( cryptContext, decryptContext ) )
503  return( FALSE );
504 
505  /* Clean up */
506  destroyContexts( CRYPT_UNUSED, cryptContext, decryptContext );
507 
508  return( TRUE );
509  }
510 
511 int testDeriveKey( void )
512  {
514  C_STR shortUserKey = TEXT( "12345678" );
515  C_STR medUserKey = TEXT( "This is a long user key for key derivation testing" );
516  C_STR longUserKey = TEXT( "This is a really long user key that exceeds the HMAC input limit for keys" );
517  BYTE buffer[ 8 ];
518  int value, status;
519 
520  puts( "Testing key derivation..." );
521 
522  /* Make sure that we can get/set the keying values with equivalent
523  systemwide settings using either the context-specific or global
524  option attributes */
525  status = cryptCreateContext( &cryptContext, CRYPT_UNUSED,
526  CRYPT_ALGO_DES );
527  if( cryptStatusError( status ) )
528  return( FALSE );
529  status = cryptSetAttribute( cryptContext,
531  if( cryptStatusOK( status ) )
532  status = cryptGetAttribute( cryptContext,
534  &value );
535  cryptDestroyContext( cryptContext );
536  if( cryptStatusError( status ) || value != 5 )
537  {
538  if( cryptStatusError( status ) )
539  value = -1; /* Set dummy value if read failed */
540  printf( "Failed to get/set context attribute via equivalent global "
541  "attribute, error\ncode %d, value %d (should be 5), line "
542  "%d.\n", status, value, __LINE__ );
543  return( FALSE );
544  }
545 
546  /* Test the derivation of keys from short, medium, and long passwords */
547  status = deriveKey( shortUserKey, paramStrlen( shortUserKey ), FALSE );
548  if( status )
549  status = deriveKey( medUserKey, paramStrlen( medUserKey ), FALSE );
550  if( status )
551  status = deriveKey( longUserKey, paramStrlen( longUserKey ), FALSE );
552  if( !status )
553  return( FALSE );
554 
555  /* Test the derivation process using a non-default hash algorithm */
556  status = deriveKey( shortUserKey, paramStrlen( shortUserKey ), TRUE );
557  if( !status )
558  return( FALSE );
559 
560  /* Test the derivation process using fixed test data: password =
561  "password", salt = { 0x12 0x34 0x56 0x78 0x78 0x56 0x34 0x12 },
562  iterations = 5 */
563  status = cryptCreateContext( &cryptContext, CRYPT_UNUSED,
564  CRYPT_ALGO_DES );
565  if( cryptStatusError( status ) )
566  return( FALSE );
569  "\x12\x34\x56\x78\x78\x56\x34\x12", 8 );
572  TEXT( "password" ),
573  paramStrlen( TEXT( "password" ) ) );
574  memset( buffer, 0, 8 );
575  cryptEncrypt( cryptContext, buffer, 8 );
576  cryptDestroyContext( cryptContext );
577  if( memcmp( buffer, "\x9B\xBD\x78\xFC\x11\xA3\xA9\x08", 8 ) )
578  {
579  puts( "Derived key value doesn't match predefined test value." );
580  return( FALSE );
581  }
582 
583  puts( "Key exchange via derived key succeeded.\n" );
584  return( TRUE );
585  }
586 
587 /* Test the code to export/import an encrypted key via conventional
588  encryption.
589 
590  To create the CMS PWRI test vectors, substitute the following code for the
591  normal key load:
592 
593  const C_STR userKey = "password";
594  const int userKeyLength = 8;
595 
596  cryptCreateContext( &sessionKeyContext1, CRYPT_UNUSED, CRYPT_ALGO_DES );
597  cryptSetAttributeString( sessionKeyContext1, CRYPT_CTXINFO_KEY,
598  "\x8C\x63\x7D\x88\x72\x23\xA2\xF9", 8 );
599  cryptCreateContext( &cryptContext, CRYPT_UNUSED, CRYPT_ALGO_DES );
600  cryptSetAttribute( cryptContext, CRYPT_CTXINFO_KEYING_ITERATIONS, 5 );
601  cryptSetAttributeString( cryptContext, CRYPT_CTXINFO_KEYING_SALT,
602  "\x12\x34\x56\x78\x78\x56\x34\x12", 8 );
603  status = cryptSetAttributeString( cryptContext,
604  CRYPT_CTXINFO_KEYING_VALUE,
605  userKey, userKeyLength );
606 
607  To create the PKCS #5 v2.0 Amd.1 test vectors use:
608 
609  const C_STR userKey = "foo123";
610  const int userKeyLength = 6;
611 
612  cryptCreateContext( &cryptContext, CRYPT_UNUSED, CRYPT_ALGO_3DES );
613  cryptSetAttribute( cryptContext, CRYPT_CTXINFO_KEYING_ITERATIONS, 1000 );
614  cryptSetAttributeString( cryptContext, CRYPT_CTXINFO_KEYING_SALT,
615  "\x12\x3E\xFF\x3C\x4A\x72\x12\x9C", 8 );
616  status = cryptSetAttributeString( cryptContext,
617  CRYPT_CTXINFO_KEYING_VALUE,
618  userKey, userKeyLength ); */
619 
620 typedef enum { AES_NONE, AES_128_128, AES_128_256,
621  AES_256_128, AES_256_256 } AES_KEYSIZE_OPT;
622  /* First parameter = session key, second
623  parameter = wrap key */
624 
625 static int conventionalExportImport( const CRYPT_CONTEXT cryptContext,
626  const CRYPT_CONTEXT sessionKeyContext1,
627  const CRYPT_CONTEXT sessionKeyContext2,
628  const BOOLEAN useAltAlgo,
629  const AES_KEYSIZE_OPT aesKeysizeOpt )
630  {
632  CRYPT_CONTEXT decryptContext;
633  BYTE *buffer;
634  const C_STR userKey = TEXT( "All n-entities must communicate with other n-entities via n-1 entiteeheehees" );
635  const int userKeyLength = paramStrlen( userKey );
636  int length, status;
637 
638  /* Set the key for the exporting context */
639  status = cryptSetAttributeString( cryptContext, CRYPT_CTXINFO_KEYING_SALT,
640  "\x12\x34\x56\x78\x78\x56\x34\x12", 8 );
641  if( cryptStatusOK( status ) && useAltAlgo )
642  status = cryptSetAttribute( cryptContext, CRYPT_CTXINFO_KEYING_ALGO,
644  if( cryptStatusOK( status ) )
645  status = cryptSetAttributeString( cryptContext,
647  userKey, userKeyLength );
648  if( cryptStatusError( status ) )
649  {
650  printf( "cryptSetAttributeString() failed with error code %d, line "
651  "%d.\n", status, __LINE__ );
652  return( FALSE );
653  }
654 
655  /* Find out how big the exported key will be */
656  status = cryptExportKey( NULL, 0, &length, cryptContext,
657  sessionKeyContext1 );
658  if( cryptStatusError( status ) )
659  {
660  printf( "cryptExportKey() failed with error code %d, line %d.\n",
661  status, __LINE__ );
662  return( FALSE );
663  }
664  printf( "cryptExportKey() reports exported key object will be %d bytes "
665  "long\n", length );
666  if( ( buffer = malloc( length ) ) == NULL )
667  return( FALSE );
668 
669  /* Export the session information */
670  status = cryptExportKey( buffer, length, &length, cryptContext,
671  sessionKeyContext1 );
672  if( cryptStatusError( status ) )
673  {
674  printf( "cryptExportKey() failed with error code %d, line %d.\n",
675  status, __LINE__ );
676  free( buffer );
677  return( FALSE );
678  }
679 
680  /* Query the encrypted key object */
681  status = cryptQueryObject( buffer, length, &cryptObjectInfo );
682  if( cryptStatusError( status ) )
683  {
684  printf( "cryptQueryObject() failed with error code %d, line %d.\n",
685  status, __LINE__ );
686  free( buffer );
687  return( FALSE );
688  }
689  printf( "cryptQueryObject() reports object type %d, algorithm %d, mode "
690  "%d.\n", cryptObjectInfo.objectType, cryptObjectInfo.cryptAlgo,
691  cryptObjectInfo.cryptMode );
692  if( aesKeysizeOpt == AES_NONE )
693  debugDump( "kek", buffer, length );
694  else
695  {
696  const char *fileName = ( aesKeysizeOpt == AES_128_128 ) ? \
697  "kek_aes128_128" : \
698  ( aesKeysizeOpt == AES_128_256 ) ? \
699  "kek_aes128_256" : \
700  ( aesKeysizeOpt == AES_256_128 ) ? \
701  "kek_aes256_128" : "kek_aes256_256";
702  debugDump( fileName, buffer, length );
703  }
704  if( useAltAlgo && cryptObjectInfo.hashAlgo != CRYPT_ALGO_HMAC_SHA2 )
705  {
706  printf( "Key wrap with algorithm CRYPT_ALGO_HMAC_SHA2 reported "
707  "hash algorithm as %d, line %d.\n", status, __LINE__ );
708  free( buffer );
709  return( FALSE );
710  }
711 
712  /* Recreate the session key by importing the encrypted key */
713  status = cryptCreateContext( &decryptContext, CRYPT_UNUSED,
714  cryptObjectInfo.cryptAlgo );
715  if( cryptStatusError( status ) )
716  {
717  printf( "cryptCreateContext() failed with error code %d, line %d.\n",
718  status, __LINE__ );
719  free( buffer );
720  return( FALSE );
721  }
722  cryptSetAttribute( decryptContext, CRYPT_CTXINFO_MODE,
723  cryptObjectInfo.cryptMode );
724  status = cryptSetAttributeString( decryptContext,
726  cryptObjectInfo.salt,
727  cryptObjectInfo.saltSize );
728  if( cryptStatusOK( status ) && useAltAlgo )
729  status = cryptSetAttribute( decryptContext,
731  cryptObjectInfo.hashAlgo );
732  if( cryptStatusOK( status ) && \
733  ( aesKeysizeOpt == AES_128_256 || aesKeysizeOpt == AES_256_256 ) )
734  {
735  /* The CRYPT_OBJECT_INFO structure doesn't contain an entry for the
736  key size because it hadn't been needed previously and it can't be
737  changed now without breaking the ABI, so we have to explicitly
738  set the non-default key size via an externally-supplied parameter
739  until there's a rev.of the minor version and we can modify the
740  ABI */
741  status = cryptSetAttribute( decryptContext,
742  CRYPT_CTXINFO_KEYSIZE, 32 );
743  }
744  if( cryptStatusOK( status ) )
745  status = cryptSetAttributeString( decryptContext,
747  userKey, userKeyLength );
748  if( cryptStatusError( status ) )
749  {
750  printf( "cryptSetAttributeString() failed with error code %d, line "
751  "%d.\n", status, __LINE__ );
752  return( FALSE );
753  }
754  status = cryptImportKey( buffer, length, decryptContext,
755  sessionKeyContext2 );
756  if( cryptStatusError( status ) )
757  {
758  printf( "cryptImportKey() failed with error code %d, line %d.\n",
759  status, __LINE__ );
760  free( buffer );
761  return( FALSE );
762  }
763 
764  /* Make sure that the two keys match */
765  if( !compareSessionKeys( sessionKeyContext1, sessionKeyContext2 ) )
766  return( FALSE );
767 
768  /* If we're using variable-length keys, make sure that the lengths are
769  right. We only need to check one of the two contexts since the fact
770  that the key sizes are the same has already been confirmed */
771  if( aesKeysizeOpt != AES_NONE )
772  {
773  const int sessionKeySize = ( aesKeysizeOpt == AES_128_128 || \
774  aesKeysizeOpt == AES_128_256 ) ? \
775  16 : 32;
776  const int wrapKeySize = ( aesKeysizeOpt == AES_128_128 || \
777  aesKeysizeOpt == AES_256_128 ) ? \
778  16 : 32;
779 
780  status = cryptGetAttribute( sessionKeyContext1,
781  CRYPT_CTXINFO_KEYSIZE, &length );
782  if( cryptStatusError( status ) || length != sessionKeySize )
783  {
784  printf( "AES session key size is incorrect, line %d.\n",
785  __LINE__ );
786  return( FALSE );
787  }
788  status = cryptGetAttribute( decryptContext,
789  CRYPT_CTXINFO_KEYSIZE, &length );
790  if( cryptStatusError( status ) || length != wrapKeySize )
791  {
792  printf( "AES wrap key size is incorrect, line %d.\n",
793  __LINE__ );
794  return( FALSE );
795  }
796  }
797 
798  /* Clean up */
799  cryptDestroyContext( decryptContext );
800  free( buffer );
801  return( TRUE );
802  }
803 
804 static int testConv3DES( void )
805  {
807  CRYPT_CONTEXT sessionKeyContext1, sessionKeyContext2;
808  int status;
809 
810  puts( "Testing 3DES conventional key export/import via Blowfish..." );
811 
812  /* Create triple-DES contexts for the session key */
813  status = cryptCreateContext( &sessionKeyContext1, CRYPT_UNUSED,
814  CRYPT_ALGO_3DES );
815  if( cryptStatusOK( status ) )
816  status = cryptSetAttribute( sessionKeyContext1, CRYPT_CTXINFO_MODE,
817  CRYPT_MODE_CFB );
818  if( cryptStatusOK( status ) )
819  status = cryptGenerateKey( sessionKeyContext1 );
820  if( cryptStatusOK( status ) )
821  status = cryptCreateContext( &sessionKeyContext2, CRYPT_UNUSED,
822  CRYPT_ALGO_3DES );
823  if( cryptStatusOK( status ) )
824  status = cryptSetAttribute( sessionKeyContext2, CRYPT_CTXINFO_MODE,
825  CRYPT_MODE_CFB );
826  if( cryptStatusError( status ) )
827  {
828  printf( "Session key context setup failed with error code %d, line "
829  "%d.\n", status, __LINE__ );
830  return( FALSE );
831  }
832 
833  /* Create a Blowfish context to export the session key */
834  status = cryptCreateContext( &cryptContext, CRYPT_UNUSED,
836  if( cryptStatusError( status ) )
837  {
838  printf( "Export key context setup failed with error code %d, line "
839  "%d.\n", status, __LINE__ );
840  return( FALSE );
841  }
842 
843  /* Export the key */
844  if( !conventionalExportImport( cryptContext, sessionKeyContext1,
845  sessionKeyContext2, FALSE, AES_NONE ) )
846  return( FALSE );
847  cryptDestroyContext( cryptContext );
848  destroyContexts( CRYPT_UNUSED, sessionKeyContext1, sessionKeyContext2 );
849  puts( "Export/import of 3DES key via user-key-based Blowfish "
850  "conventional\n encryption succeeded." );
851 
852  return( TRUE );
853  }
854 
855 static int testConvAES( const AES_KEYSIZE_OPT aesKeysizeOpt )
856  {
858  CRYPT_CONTEXT sessionKeyContext1, sessionKeyContext2;
859  const char *aesKey1Name = ( aesKeysizeOpt == AES_128_128 || \
860  aesKeysizeOpt == AES_128_256 ) ? \
861  "AES-128" : "AES-256";
862  const char *aesKey2Name = ( aesKeysizeOpt == AES_128_128 || \
863  aesKeysizeOpt == AES_256_128 ) ? \
864  "AES-128" : "AES-256";
865  int status;
866 
867  printf( "Testing %s conventional key export/import via %s...\n",
868  aesKey1Name, aesKey2Name );
869 
870  /* Create AES contexts for the session key and another AES context to
871  export the session key. In addition to using AES we use a non-
872  default PRF algorithm */
873  status = cryptCreateContext( &sessionKeyContext1, CRYPT_UNUSED,
875  if( cryptStatusOK( status ) )
876  status = cryptSetAttribute( sessionKeyContext1, CRYPT_CTXINFO_MODE,
877  CRYPT_MODE_CFB );
878  if( cryptStatusOK( status ) && \
879  ( aesKeysizeOpt == AES_256_128 || aesKeysizeOpt == AES_256_256 ) )
880  status = cryptSetAttribute( sessionKeyContext1,
881  CRYPT_CTXINFO_KEYSIZE, 32 );
882  if( cryptStatusOK( status ) )
883  status = cryptGenerateKey( sessionKeyContext1 );
884  if( cryptStatusOK( status ) )
885  {
886  status = cryptCreateContext( &sessionKeyContext2, CRYPT_UNUSED,
888  cryptSetAttribute( sessionKeyContext2, CRYPT_CTXINFO_MODE,
889  CRYPT_MODE_CFB );
890  }
891  if( cryptStatusError( status ) )
892  {
893  printf( "Session key context setup failed with error code %d, line "
894  "%d.\n", status, __LINE__ );
895  return( FALSE );
896  }
897  status = cryptCreateContext( &cryptContext, CRYPT_UNUSED,
899  if( cryptStatusOK( status ) && \
900  ( aesKeysizeOpt == AES_128_256 || aesKeysizeOpt == AES_256_256 ) )
901  status = cryptSetAttribute( cryptContext,
902  CRYPT_CTXINFO_KEYSIZE, 32 );
903  if( cryptStatusError( status ) )
904  {
905  printf( "Export key context setup failed with error code %d, line "
906  "%d.\n", status, __LINE__ );
907  return( FALSE );
908  }
909 
910  /* Export the key */
911  if( !conventionalExportImport( cryptContext, sessionKeyContext1,
912  sessionKeyContext2, TRUE,
913  aesKeysizeOpt ) )
914  return( FALSE );
915  cryptDestroyContext( cryptContext );
916  destroyContexts( CRYPT_UNUSED, sessionKeyContext1, sessionKeyContext2 );
917  printf( "Export/import of %s key via user-key-based %s conventional "
918  "encryption\n succeeded.\n", aesKey1Name, aesKey2Name );
919 
920  return( TRUE );
921  }
922 
924  {
925  if( !testConv3DES() )
926  return( FALSE );
927  if( !testConvAES( AES_128_128 ) )
928  return( FALSE );
929  if( !testConvAES( AES_128_256 ) )
930  return( FALSE );
931  if( !testConvAES( AES_256_128 ) )
932  return( FALSE );
933  if( !testConvAES( AES_256_256 ) )
934  return( FALSE );
935  putchar( '\n' );
936 
937  return( TRUE );
938  }
939 
940 int testMACExportImport( void )
941  {
943  CRYPT_CONTEXT cryptContext, decryptContext;
944  CRYPT_CONTEXT macContext1, macContext2;
945  BYTE mac1[ CRYPT_MAX_HASHSIZE ], mac2[ CRYPT_MAX_HASHSIZE ];
946  C_STR userKey = TEXT( "This is a long user key for MAC testing" );
947  BYTE *buffer;
948  int userKeyLength = paramStrlen( userKey );
949  int status, length1, length2;
950 
951  puts( "Testing MAC key export/import..." );
952 
953  /* Create HMAC-SHA1 contexts for the MAC key */
954  status = cryptCreateContext( &macContext1, CRYPT_UNUSED,
956  if( cryptStatusOK( status ) )
957  status = cryptGenerateKey( macContext1 );
958  if( cryptStatusOK( status ) )
959  status = cryptCreateContext( &macContext2, CRYPT_UNUSED,
961  if( cryptStatusError( status ) )
962  return( FALSE );
963 
964  /* Create a 3DES encryption context to export the MAC key */
965  status = cryptCreateContext( &cryptContext, CRYPT_UNUSED,
966  CRYPT_ALGO_3DES );
967  if( cryptStatusError( status ) )
968  return( FALSE );
970  "\x12\x34\x56\x78\x78\x56\x34\x12", 8 );
971  status = cryptSetAttributeString( cryptContext,
973  userKey, userKeyLength );
974  if( cryptStatusError( status ) )
975  return( FALSE );
976 
977  /* Find out how big the exported key will be */
978  status = cryptExportKey( NULL, 0, &length1, cryptContext, macContext1 );
979  if( cryptStatusError( status ) )
980  {
981  printf( "cryptExportKey() failed with error code %d, line %d.\n",
982  status, __LINE__ );
983  return( FALSE );
984  }
985  printf( "cryptExportKey() reports exported key object will be %d bytes "
986  "long\n", length1 );
987  if( ( buffer = malloc( length1 ) ) == NULL )
988  return( FALSE );
989 
990  /* Export the MAC information */
991  status = cryptExportKey( buffer, length1, &length1, cryptContext,
992  macContext1 );
993  if( cryptStatusError( status ) )
994  {
995  printf( "cryptExportKey() failed with error code %d, line %d.\n",
996  status, __LINE__ );
997  free( buffer );
998  return( FALSE );
999  }
1000 
1001  /* Query the encrypted key object */
1002  status = cryptQueryObject( buffer, length1, &cryptObjectInfo );
1003  if( cryptStatusError( status ) )
1004  {
1005  printf( "cryptQueryObject() failed with error code %d, line %d.\n",
1006  status, __LINE__ );
1007  free( buffer );
1008  return( FALSE );
1009  }
1010  printf( "cryptQueryObject() reports object type %d, algorithm %d, mode "
1011  "%d.\n", cryptObjectInfo.objectType, cryptObjectInfo.cryptAlgo,
1012  cryptObjectInfo.cryptMode );
1013  debugDump( "kek_mac", buffer, length1 );
1014 
1015  /* Recreate the MAC key by importing the encrypted key */
1016  status = cryptCreateContext( &decryptContext, CRYPT_UNUSED,
1017  cryptObjectInfo.cryptAlgo );
1018  if( cryptStatusError( status ) )
1019  {
1020  printf( "cryptCreateContext() failed with error code %d, line %d.\n",
1021  status, __LINE__ );
1022  free( buffer );
1023  return( FALSE );
1024  }
1025  cryptSetAttribute( cryptContext, CRYPT_CTXINFO_MODE,
1026  cryptObjectInfo.cryptMode );
1028  cryptObjectInfo.salt, cryptObjectInfo.saltSize );
1029  status = cryptSetAttributeString( decryptContext,
1031  userKey, userKeyLength );
1032  if( cryptStatusOK( status ) )
1033  status = cryptImportKey( buffer, length1, decryptContext,
1034  macContext2 );
1035  free( buffer );
1036  if( cryptStatusError( status ) )
1037  {
1038  printf( "cryptImportKey() failed with error code %d, line %d.\n",
1039  status, __LINE__ );
1040  return( FALSE );
1041  }
1042 
1043  /* Make sure that the two MAC keys match */
1044  cryptEncrypt( macContext1, "1234", 4 );
1045  status = cryptEncrypt( macContext1, "", 0 );
1046  if( cryptStatusOK( status ) )
1047  {
1048  cryptEncrypt( macContext2, "1234", 4 );
1049  status = cryptEncrypt( macContext2, "", 0 );
1050  }
1051  if( cryptStatusOK( status ) )
1052  status = cryptGetAttributeString( macContext1,
1054  mac1, &length1 );
1055  if( cryptStatusOK( status ) )
1056  status = cryptGetAttributeString( macContext2,
1058  mac2, &length2 );
1059  if( cryptStatusError( status ) )
1060  {
1061  printf( "MAC operation failed with error code %d, line %d.\n",
1062  status, __LINE__ );
1063  return( FALSE );
1064  }
1065  if( ( length1 != length2 ) || memcmp( mac1, mac2, length1 ) || \
1066  !memcmp( mac1, "\x00\x00\x00\x00\x00\x00\x00\x00", 8 ) || \
1067  !memcmp( mac2, "\x00\x00\x00\x00\x00\x00\x00\x00", 8 ) )
1068  {
1069  puts( "Data MAC'd with key1 != data MAC'd with key2." );
1070  return( FALSE );
1071  }
1072 
1073  /* Clean up */
1074  destroyContexts( CRYPT_UNUSED, macContext1, macContext2 );
1075  destroyContexts( CRYPT_UNUSED, cryptContext, decryptContext );
1076  printf( "Export/import of MAC key via user-key-based triple DES "
1077  "conventional\n encryption succeeded.\n\n" );
1078  return( TRUE );
1079  }
1080 
1081 /* Test the code to export/import an encrypted key and sign data. We're not
1082  as picky with error-checking here since most of the functions have just
1083  executed successfully. We check every algorithm type since there are
1084  different code paths for DLP and non-DLP PKCs */
1085 
1086 int testKeyExportImport( void )
1087  {
1088  if( !keyExportImport( "RSA", CRYPT_ALGO_RSA, CRYPT_UNUSED, CRYPT_UNUSED, CRYPT_FORMAT_CRYPTLIB ) )
1089  return( FALSE ); /* RSA */
1091  !keyExportImport( "Elgamal", CRYPT_ALGO_ELGAMAL, CRYPT_UNUSED, CRYPT_UNUSED, CRYPT_FORMAT_CRYPTLIB ) )
1092  return( FALSE ); /* Elgamal */
1093 #ifdef USE_PGP
1094  if( !keyExportImport( "RSA", CRYPT_ALGO_RSA, CRYPT_UNUSED, CRYPT_UNUSED, CRYPT_FORMAT_PGP ) )
1095  return( FALSE ); /* RSA, PGP format */
1096  return( keyExportImport( "Elgamal", CRYPT_ALGO_ELGAMAL, CRYPT_UNUSED, CRYPT_UNUSED, CRYPT_FORMAT_PGP ) );
1097  /* Elgamal, PGP format */
1098 #else
1099  return( TRUE );
1100 #endif /* USE_PGP */
1101  }
1102 
1103 int testSignData( void )
1104  {
1106  return( FALSE ); /* RSA */
1108  return( FALSE ); /* RSA, side-channel attack protection */
1109  if( !signData( "RSA with SHA2", CRYPT_ALGO_RSA, CRYPT_UNUSED, CRYPT_UNUSED, FALSE, TRUE, CRYPT_FORMAT_CRYPTLIB ) )
1110  return( FALSE ); /* RSA with SHA2 */
1112  return( FALSE ); /* DSA */
1115  return( FALSE ); /* ECDSA */
1116 #ifdef USE_PGP
1117  if( !signData( "RSA", CRYPT_ALGO_RSA, CRYPT_UNUSED, CRYPT_UNUSED, FALSE, FALSE, CRYPT_FORMAT_PGP ) )
1118  return( FALSE ); /* RSA, PGP format */
1119  return( signData( "DSA", CRYPT_ALGO_DSA, CRYPT_UNUSED, CRYPT_UNUSED, FALSE, FALSE, CRYPT_FORMAT_PGP ) );
1120  /* DSA, PGP format */
1121 #else
1122  return( TRUE );
1123 #endif /* USE_PGP */
1124  }
1125 
1126 /* Test normal and asynchronous public-key generation */
1127 
1128 static int keygen( const CRYPT_ALGO_TYPE cryptAlgo, const char *algoName )
1129  {
1131  BYTE buffer[ BUFFER_SIZE ];
1132  int length, status;
1133 
1134  printf( "Testing %s key generation...\n", algoName );
1135 
1136  /* Create an encryption context and generate a (short) key into it.
1137  Generating a minimal-length 512 bit key is faster than the default
1138  1-2K bit keys */
1139  status = cryptCreateContext( &cryptContext, CRYPT_UNUSED, cryptAlgo );
1140  if( cryptStatusError( status ) )
1141  return( FALSE );
1143  TEXT( "Private key" ),
1144  paramStrlen( TEXT( "Private key" ) ) );
1145  status = cryptGenerateKey( cryptContext );
1146  if( cryptStatusError( status ) )
1147  {
1148  printf( "cryptGenerateKey() failed with error code %d, line %d.\n",
1149  status, __LINE__ );
1150  return( FALSE );
1151  }
1152 
1153  /* Perform a test operation to check the new key */
1154  switch( cryptAlgo )
1155  {
1156  case CRYPT_ALGO_RSA:
1157  case CRYPT_ALGO_DSA:
1158  case CRYPT_ALGO_ECDSA:
1159  {
1161  BYTE hashBuffer[] = "abcdefghijklmnopqrstuvwxyz";
1162 
1163  /* Create an SHA hash context and hash the test buffer */
1164  status = cryptCreateContext( &hashContext, CRYPT_UNUSED,
1165  CRYPT_ALGO_SHA );
1166  if( cryptStatusError( status ) )
1167  return( FALSE );
1168  cryptEncrypt( hashContext, hashBuffer, 26 );
1169  cryptEncrypt( hashContext, hashBuffer, 0 );
1170 
1171  /* Sign the hashed data and check the signature */
1172  status = cryptCreateSignature( buffer, BUFFER_SIZE, &length,
1173  cryptContext, hashContext );
1174  if( cryptStatusOK( status ) )
1175  status = cryptCheckSignature( buffer, length, cryptContext,
1176  hashContext );
1177 
1178  /* Clean up */
1179  cryptDestroyContext( hashContext );
1180  cryptDestroyContext( cryptContext );
1181  if( cryptStatusError( status ) )
1182  {
1183  printf( "Sign/signature check with generated key failed "
1184  "with error code %d, line %d.\n", status,
1185  __LINE__ );
1186  return( FALSE );
1187  }
1188  break;
1189  }
1190 
1191  case CRYPT_ALGO_ELGAMAL:
1192  {
1193  CRYPT_CONTEXT sessionKeyContext1, sessionKeyContext2;
1194 
1195  /* Test the key exchange */
1196  status = cryptCreateContext( &sessionKeyContext1, CRYPT_UNUSED,
1197  CRYPT_ALGO_DES );
1198  if( cryptStatusError( status ) )
1199  return( FALSE );
1200  status = cryptCreateContext( &sessionKeyContext2,
1202  if( cryptStatusError( status ) )
1203  {
1204  cryptDestroyContext( sessionKeyContext1 );
1205  return( FALSE );
1206  }
1207  if( cryptStatusOK( status ) )
1208  status = cryptGenerateKey( sessionKeyContext1 );
1209  if( cryptStatusError( status ) )
1210  return( FALSE );
1211  status = cryptExportKey( buffer, BUFFER_SIZE, &length,
1212  cryptContext, sessionKeyContext1 );
1213  if( cryptStatusOK( status ) )
1214  status = cryptImportKey( buffer, length, cryptContext,
1215  sessionKeyContext2 );
1216  cryptDestroyContext( cryptContext );
1217  if( cryptStatusError( status ) )
1218  {
1219  destroyContexts( CRYPT_UNUSED, sessionKeyContext1,
1220  sessionKeyContext2 );
1221  printf( "Key exchange with generated key failed with error "
1222  "code %d, line %d.\n", status, __LINE__ );
1223  return( FALSE );
1224  }
1225 
1226  /* Make sure that the two keys match */
1227  if( !compareSessionKeys( sessionKeyContext1,
1228  sessionKeyContext2 ) )
1229  return( FALSE );
1230 
1231  /* Clean up */
1232  destroyContexts( CRYPT_UNUSED, sessionKeyContext1,
1233  sessionKeyContext2 );
1234  break;
1235  }
1236 
1237  case CRYPT_ALGO_DH:
1238  case CRYPT_ALGO_ECDH:
1239  {
1240 KLUDGE_WARN( "DH/ECDH test because of absence of DH/ECDH key exchange mechanism" );
1241 cryptDestroyContext( cryptContext );
1242 return( TRUE );
1243 
1244 #if 0 /* Get rid if unreachable-code warnings */
1245  CRYPT_CONTEXT dhContext;
1246  CRYPT_CONTEXT sessionKeyContext1, sessionKeyContext2;
1247 
1248  /* Test the key exchange */
1249  status = cryptCreateContext( &sessionKeyContext1, CRYPT_UNUSED,
1250  CRYPT_ALGO_DES );
1251  if( cryptStatusOK( status ) )
1252  status = cryptCreateContext( &sessionKeyContext2,
1254  if( cryptStatusOK( status ) )
1255  status = cryptCreateContext( &dhContext, CRYPT_UNUSED,
1256  CRYPT_ALGO_DH );
1257  if( cryptStatusError( status ) )
1258  return( FALSE );
1259  status = cryptExportKey( buffer, BUFFER_SIZE, &length,
1260  cryptContext, sessionKeyContext1 );
1261  if( cryptStatusOK( status ) )
1262  status = cryptImportKey( buffer, length, dhContext,
1263  sessionKeyContext2 );
1264  if( cryptStatusOK( status ) )
1265  status = cryptExportKey( buffer, BUFFER_SIZE, &length,
1266  dhContext, sessionKeyContext2 );
1267  if( cryptStatusOK( status ) )
1268  status = cryptImportKey( buffer, length, cryptContext,
1269  sessionKeyContext1 );
1270  cryptDestroyContext( cryptContext );
1271  cryptDestroyContext( dhContext );
1272  if( cryptStatusError( status ) )
1273  {
1274  destroyContexts( CRYPT_UNUSED, sessionKeyContext1,
1275  sessionKeyContext2 );
1276  printf( "Key exchange with generated key failed with error "
1277  "code %d, line %d.\n", status, __LINE__ );
1278  return( FALSE );
1279  }
1280 
1281  /* Make sure that the two keys match */
1282  if( !compareSessionKeys( sessionKeyContext1,
1283  sessionKeyContext2 ) )
1284  return( FALSE );
1285 
1286  /* Clean up */
1287  destroyContexts( CRYPT_UNUSED, sessionKeyContext1,
1288  sessionKeyContext2 );
1289  break;
1290 #endif /* 0 */
1291  }
1292 
1293  default:
1294  printf( "Unexpected encryption algorithm %d found, line %d.\n",
1295  cryptAlgo, __LINE__ );
1296  return( FALSE );
1297  }
1298 
1299  printf( "%s key generation succeeded.\n", algoName );
1300  return( TRUE );
1301  }
1302 
1303 int testKeygen( void )
1304  {
1305  if( !keygen( CRYPT_ALGO_RSA, "RSA" ) )
1306  return( FALSE );
1307  if( !keygen( CRYPT_ALGO_DSA, "DSA" ) )
1308  return( FALSE );
1310  !keygen( CRYPT_ALGO_ELGAMAL, "Elgamal" ) )
1311  return( FALSE );
1312  if( !keygen( CRYPT_ALGO_DH, "DH" ) )
1313  return( FALSE );
1315  !keygen( CRYPT_ALGO_ECDSA, "ECDSA" ) )
1316  return( FALSE );
1318  !keygen( CRYPT_ALGO_ECDH, "ECDH" ) )
1319  return( FALSE );
1320  printf( "\n" );
1321  return( TRUE );
1322  }
1323 
1324 int testKeygenAsync( void )
1325  {
1326 #if !defined( UNIX_THREADS ) && !defined( WINDOWS_THREADS ) && \
1327  !defined( OS2_THREADS )
1328  return( TRUE );
1329 #elif 1
1330  return( TRUE ); /* Removed for the 3.4 release */
1331 #else
1333  BYTE hashBuffer[] = "abcdefghijklmnopqrstuvwxyz";
1334  BYTE buffer[ BUFFER_SIZE ];
1335  int cancelCount = 0, length, status;
1336 
1337  puts( "Testing asynchronous key generation..." );
1338 
1339  /* Create an encryption context and generate a longish (3K bit) key
1340  into it. This ensures that we can see the async operation in
1341  action, anything smaller and it's done almost immediately (note
1342  that this may cause problems with some external implementations
1343  that cap the keysize at 2K bits) */
1344  status = cryptCreateContext( &cryptContext, CRYPT_UNUSED,
1345  CRYPT_ALGO_RSA );
1346  if( cryptStatusError( status ) )
1347  return( FALSE );
1349  TEXT( "Private key" ),
1350  paramStrlen( TEXT( "Private key" ) ) );
1351  status = cryptGenerateKeyAsync( cryptContext );
1352  if( cryptStatusError( status ) )
1353  {
1354  printf( "cryptGenerateKeyAsync() failed with error code %d, line "
1355  "%d.\n", status, __LINE__ );
1356  return( FALSE );
1357  }
1358 
1359  /* Hang around a bit to allow things to start. This value is a bit of a
1360  difficult quantity to get right since VC++ can spend longer than the
1361  startup time thrashing the drive doing nothing so it has to be high,
1362  but on faster PC's even a 3K bit key can be generated in a few
1363  seconds, so it can't be too high or the keygen will have finished.
1364  The following value was safe for a 700MHz PIII, but the next step
1365  would be to move to 4K bit keys (4096 bits, 512 in the above keygen
1366  call) */
1367  printf( "Delaying 2s to allow keygen to start..." );
1368  delayThread( 2 );
1369  puts( "done." );
1370 
1371  /* Check that the async keygen is still in progress */
1372  status = cryptAsyncQuery( cryptContext );
1373  if( status == CRYPT_ERROR_TIMEOUT )
1374  puts( "Async keygen in progress." );
1375  else
1376  {
1377  /* If the machine's really fast, the keygen could have completed
1378  already */
1379  if( status == CRYPT_OK )
1380  {
1381  printf( "The async keygen has completed before the rest of the "
1382  "test code could run.\nTo fix this, either decrease "
1383  "the startup delay on line %d\nof " __FILE__ " or "
1384  "increase the size of the key being generated to slow\n"
1385  "down the generation process.\n\n", __LINE__ - 15 );
1386  cryptDestroyContext( cryptContext );
1387 
1388  return( TRUE );
1389  }
1390 
1391  printf( "Async keygen failed with error code %d, line %d.\n", status,
1392  __LINE__ );
1393  return( FALSE );
1394  }
1395 
1396  /* Cancel the async keygen */
1397  status = cryptAsyncCancel( cryptContext );
1398  if( cryptStatusError( status ) )
1399  {
1400  printf( "cryptAsyncCancel() failed with error code %d, line %d.\n",
1401  status, __LINE__ );
1402  return( FALSE );
1403  }
1404  printf( "Cancelling async operation..." );
1405  while( cryptAsyncQuery( cryptContext ) == CRYPT_ERROR_TIMEOUT )
1406  {
1407  cancelCount++;
1408  printf( "*" );
1409  delayThread( 1 );
1410  }
1411  puts( "...done." );
1412 
1413  /* Check the context to make sure that the keygen was actually
1414  cancelled */
1415  status = cryptCreateContext( &hashContext, CRYPT_UNUSED,
1416  CRYPT_ALGO_SHA );
1417  if( cryptStatusError( status ) )
1418  return( FALSE );
1419  cryptEncrypt( hashContext, hashBuffer, 26 );
1420  cryptEncrypt( hashContext, hashBuffer, 0 );
1421  status = cryptCreateSignature( buffer, BUFFER_SIZE, &length,
1422  cryptContext, hashContext );
1423  if( cryptStatusOK( status ) )
1424  {
1425  /* We have to be a bit careful here to try and eliminate false
1426  positives due to fast CPUs. As a rule of thumb, it shouldn't
1427  take more than 1s for a cancel to propagate through the system.
1428  On the other hand we can also run into problems with very slow
1429  CPUs that take so long to get started that the cancel never
1430  arrives, to handle the entire spectrum of system types we just
1431  print a warning but don't abort if there's a problem */
1432  if( cancelCount <= 1 )
1433  {
1434  puts( "The async keygen completed even though the operation was "
1435  "cancelled. This was\nprobably because the CPU was fast "
1436  "enough that the keygen completed before the\ncancel could "
1437  "take effect." );
1438  }
1439  else
1440  {
1441  puts( "The async keygen completed even though the operation was "
1442  "cancelled. The\ncancel should have stopped the keygen from "
1443  "completing.\n" );
1444  }
1445  }
1446 
1447  /* Clean up */
1448  cryptDestroyContext( cryptContext );
1449  cryptDestroyContext( hashContext );
1450  puts( "Asynchronous key generation succeeded.\n" );
1451  return( TRUE );
1452 #endif /* Systems with threading support */
1453  }
1454 
1455 #endif /* TEST_MIDLEVEL */
1456 
1457 /****************************************************************************
1458 * *
1459 * Random Routines Test *
1460 * *
1461 ****************************************************************************/
1462 
1463 #ifdef TEST_RANDOM
1464 
1465 /* Test the randomness gathering routines */
1466 
1467 int testRandomRoutines( void )
1468  {
1470  int status;
1471 
1472  puts( "Testing randomness routines. This may take a few seconds..." );
1473 
1474  /* Create an encryption context to generate a key into */
1475  status = cryptCreateContext( &cryptContext, CRYPT_UNUSED,
1476  CRYPT_ALGO_DES );
1477  if( cryptStatusError( status ) )
1478  return( FALSE );
1479  status = cryptGenerateKey( cryptContext );
1480  cryptDestroyContext( cryptContext );
1481 
1482  /* Check whether we got enough randomness */
1483  if( status == CRYPT_ERROR_RANDOM )
1484  {
1485  puts( "The randomness-gathering routines can't acquire enough random information to" );
1486  puts( "allow key generation and public-key encryption to function. You will need to" );
1487  puts( "change the randomness-polling code or reconfigure your system to allow the" );
1488  puts( "randomness-gathering routines to function. The code to change can be found" );
1489  puts( "in random/<osname>.c\n" );
1490  return( FALSE );
1491  }
1492 
1493  puts( "Randomness-gathering self-test succeeded.\n" );
1494  return( TRUE );
1495  }
1496 #endif /* TEST_RANDOM */
1497 
1498 /****************************************************************************
1499 * *
1500 * High-level Routines Test *
1501 * *
1502 ****************************************************************************/
1503 
1504 #ifdef TEST_HIGHLEVEL
1505 
1506 /* Test the code to export/import a CMS key */
1507 
1508 int testKeyExportImportCMS( void )
1509  {
1511  CRYPT_KEYSET cryptKeyset;
1513  CRYPT_CONTEXT sessionKeyContext1, sessionKeyContext2;
1514  BYTE *buffer;
1515  int status, length;
1516 
1517  puts( "Testing CMS public-key export/import..." );
1518 
1519  /* Get a private key with a certificate chain attached */
1520  status = cryptKeysetOpen( &cryptKeyset, CRYPT_UNUSED, CRYPT_KEYSET_FILE,
1522  if( cryptStatusOK( status ) )
1523  {
1524  status = cryptGetPrivateKey( cryptKeyset, &cryptContext,
1527  cryptKeysetClose( cryptKeyset );
1528  }
1529  if( cryptStatusError( status ) )
1530  {
1531  printf( "Couldn't read private key, status %d, line %d.\n", status,
1532  __LINE__ );
1533  return( FALSE );
1534  }
1535 
1536  /* Create triple-DES encryption contexts for the exported and imported
1537  session keys */
1538  status = cryptCreateContext( &sessionKeyContext1, CRYPT_UNUSED,
1539  CRYPT_ALGO_3DES );
1540  if( cryptStatusOK( status ) )
1541  status = cryptGenerateKey( sessionKeyContext1 );
1542  if( cryptStatusOK( status ) )
1543  status = cryptCreateContext( &sessionKeyContext2, CRYPT_UNUSED,
1544  CRYPT_ALGO_3DES );
1545  if( cryptStatusError( status ) )
1546  return( FALSE );
1547 
1548  /* Find out how big the exported key will be */
1549  status = cryptExportKeyEx( NULL, 0, &length, CRYPT_FORMAT_SMIME,
1550  cryptContext, sessionKeyContext1 );
1551  if( cryptStatusError( status ) )
1552  {
1553  printf( "cryptExportKeyEx() failed with error code %d, line %d.\n",
1554  status, __LINE__ );
1555  return( FALSE );
1556  }
1557  printf( "cryptExportKeyEx() reports CMS exported key will be %d bytes "
1558  "long\n", length );
1559  if( ( buffer = malloc( length ) ) == NULL )
1560  return( FALSE );
1561 
1562  /* Export the key */
1563  status = cryptExportKeyEx( buffer, length, &length, CRYPT_FORMAT_SMIME,
1564  cryptContext, sessionKeyContext1 );
1565  if( cryptStatusError( status ) )
1566  {
1567  printf( "cryptExportKeyEx() failed with error code %d, line %d.\n",
1568  status, __LINE__ );
1569  free( buffer );
1570  return( FALSE );
1571  }
1572 
1573  /* Query the encrypted key object */
1574  status = cryptQueryObject( buffer, length, &cryptObjectInfo );
1575  if( cryptStatusError( status ) )
1576  {
1577  printf( "cryptQueryObject() failed with error code %d, line %d.\n",
1578  status, __LINE__ );
1579  free( buffer );
1580  return( FALSE );
1581  }
1582  printf( "cryptQueryObject() reports object type %d, algorithm %d, mode "
1583  "%d.\n", cryptObjectInfo.objectType, cryptObjectInfo.cryptAlgo,
1584  cryptObjectInfo.cryptMode );
1585  memset( &cryptObjectInfo, 0, sizeof( CRYPT_OBJECT_INFO ) );
1586  debugDump( "cms_ri", buffer, length );
1587 
1588  /* Import the encrypted key and load it into the session key context */
1589  status = cryptImportKey( buffer, length, cryptContext,
1590  sessionKeyContext2 );
1591  if( cryptStatusError( status ) )
1592  {
1593  printf( "cryptImportKey() failed with error code %d, line %d.\n",
1594  status, __LINE__ );
1595  free( buffer );
1596  return( FALSE );
1597  }
1598 
1599  /* Make sure that the two keys match */
1600  if( !compareSessionKeys( sessionKeyContext1, sessionKeyContext2 ) )
1601  return( FALSE );
1602 
1603  /* Clean up */
1604  destroyContexts( CRYPT_UNUSED, sessionKeyContext1, sessionKeyContext2 );
1605  cryptDestroyContext( cryptContext );
1606  puts( "Export/import of CMS session key succeeded.\n" );
1607  free( buffer );
1608  return( TRUE );
1609  }
1610 
1611 /* Test the code to create an CMS signature */
1612 
1613 static const CERT_DATA cmsAttributeData[] = {
1614  /* We have to be careful when setting CMS attributes because most are
1615  never used by anything so they're only available of use of obscure
1616  attributes is enabled */
1617 #ifdef USE_CMSATTR_OBSCURE
1618  /* Content type */
1620 
1621  /* Odds and ends. We can't (portably) set the opusInfo name since it's
1622  a Unicode string so we only add this one under Windows */
1623  #ifdef __WINDOWS__
1624  { CRYPT_CERTINFO_CMS_SPCOPUSINFO_NAME, IS_WCSTRING, 0, L"Program v3.0 SP2" },
1625  #endif /* __WINDOWS__ */
1626  { CRYPT_CERTINFO_CMS_SPCOPUSINFO_URL, IS_STRING, 0, TEXT( "http://bugs-r-us.com" ) },
1628 #else
1629  /* Content type */
1631 #endif /* USE_CMSATTR_OBSCURE */
1632 
1634  };
1635 
1636 static int signDataCMS( const char *description,
1637  const CRYPT_CERTIFICATE signingAttributes,
1638  const BOOLEAN isCustomAttributes )
1639  {
1640  CRYPT_KEYSET cryptKeyset;
1641  CRYPT_CERTIFICATE cmsAttributes = signingAttributes;
1643  BYTE *buffer, hashBuffer[] = "abcdefghijklmnopqrstuvwxyz";
1644  int status, length;
1645 
1646  printf( "Testing %s...\n", description );
1647 
1648  /* Create an SHA hash context and hash the test buffer */
1649  status = cryptCreateContext( &hashContext, CRYPT_UNUSED,
1650  CRYPT_ALGO_SHA );
1651  if( cryptStatusError( status ) )
1652  return( FALSE );
1653  cryptEncrypt( hashContext, hashBuffer, 26 );
1654  cryptEncrypt( hashContext, hashBuffer, 0 );
1655 
1656  /* Get a private key with a certificate chain attached */
1657  status = cryptKeysetOpen( &cryptKeyset, CRYPT_UNUSED, CRYPT_KEYSET_FILE,
1659  if( cryptStatusOK( status ) )
1660  {
1661  status = cryptGetPrivateKey( cryptKeyset, &signContext,
1664  cryptKeysetClose( cryptKeyset );
1665  }
1666  if( cryptStatusError( status ) )
1667  {
1668  printf( "Couldn't read private key, status %d, line %d.\n", status,
1669  __LINE__ );
1670  return( FALSE );
1671  }
1672 
1673  /* Find out how big the signature will be */
1674  status = cryptCreateSignatureEx( NULL, 0, &length, CRYPT_FORMAT_SMIME,
1675  signContext, hashContext, cmsAttributes );
1676  if( cryptStatusError( status ) )
1677  {
1678  printf( "cryptCreateSignatureEx() failed with error code %d, line "
1679  "%d.\n", status, __LINE__ );
1680  return( FALSE );
1681  }
1682  printf( "cryptCreateSignatureEx() reports CMS signature will be %d "
1683  "bytes long\n", length );
1684  if( ( buffer = malloc( length ) ) == NULL )
1685  return( FALSE );
1686 
1687  /* Sign the hashed data */
1688  status = cryptCreateSignatureEx( buffer, length, &length,
1689  CRYPT_FORMAT_SMIME, signContext,
1690  hashContext, cmsAttributes );
1691  if( cryptStatusError( status ) )
1692  {
1693  printf( "cryptCreateSignatureEx() failed with error code %d, line "
1694  "%d.\n", status, __LINE__ );
1695  free( buffer );
1696  return( FALSE );
1697  }
1698  debugDump( ( signingAttributes == CRYPT_USE_DEFAULT ) ? \
1699  "cms_sigd" : \
1700  ( isCustomAttributes ) ? "cms_sigc" : "cms_sig",
1701  buffer, length );
1702 
1703  /* Check the signature on the hash */
1704  status = cryptCheckSignatureEx( buffer, length, signContext, hashContext,
1705  ( cmsAttributes == CRYPT_USE_DEFAULT ) ? NULL : &cmsAttributes );
1706  if( cryptStatusError( status ) )
1707  {
1708  printf( "cryptCheckSignatureEx() failed with error code %d, line "
1709  "%d.\n", status, __LINE__ );
1710  free( buffer );
1711  return( FALSE );
1712  }
1713 
1714  /* Display the signing attributes */
1715  if( cmsAttributes != CRYPT_USE_DEFAULT )
1716  printCertInfo( cmsAttributes );
1717 
1718  /* Clean up */
1719  cryptDestroyContext( hashContext );
1720  cryptDestroyContext( signContext );
1721  cryptDestroyCert( cmsAttributes );
1722  printf( "Generation and checking of %s succeeded.\n\n", description );
1723  free( buffer );
1724  return( TRUE );
1725  }
1726 
1727 int testSignDataCMS( void )
1728  {
1729  CRYPT_CERTIFICATE cmsAttributes;
1730  const BYTE *extensionData = "\x0C\x04Test";
1731  int value, status;
1732 
1733  /* First test the basic CMS signature with default attributes (content
1734  type, signing time, and message digest) */
1735  if( !signDataCMS( "CMS signature", CRYPT_USE_DEFAULT, FALSE ) )
1736  return( FALSE );
1737 
1738  /* Create some CMS attributes and sign the data with the user-defined
1739  attributes */
1740  status = cryptCreateCert( &cmsAttributes, CRYPT_UNUSED,
1742  if( cryptStatusError( status ) || \
1743  !addCertFields( cmsAttributes, cmsAttributeData, __LINE__ ) )
1744  return( FALSE );
1745  status = signDataCMS( "complex CMS signature", cmsAttributes, FALSE );
1746  cryptDestroyCert( cmsAttributes );
1747  if( !status )
1748  return( status );
1749 
1750  /* Create some custom CMS attributes and sign those too. In order to do
1751  this we have to set the CRYPT_OPTION_CERT_SIGNUNRECOGNISEDATTRIBUTES
1752  configuration option */
1755  status = cryptCreateCert( &cmsAttributes, CRYPT_UNUSED,
1757  if( cryptStatusError( status ) )
1758  return( FALSE );
1759  status = cryptAddCertExtension( cmsAttributes, "1.2.3.4.5",
1760  CRYPT_UNUSED, extensionData, 6 );
1761  if( cryptStatusOK( status ) )
1762  {
1763  status = cryptSetAttribute( CRYPT_UNUSED,
1765  TRUE );
1766  }
1767  if( cryptStatusOK( status ) )
1768  status = signDataCMS( "CMS signature with custom attributes",
1769  cmsAttributes, TRUE );
1772  cryptDestroyCert( cmsAttributes );
1773  if( !status )
1774  return( status );
1775  return( status );
1776  }
1777 
1778 #endif /* TEST_HIGHLEVEL */