1 /****************************************************************************
2 * *
3 * cryptlib Enveloping Test Routines *
4 * Copyright Peter Gutmann 1996-2012 *
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"
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 /* Test data to use for the self-test. The PGP test data is slightly
22 different since it's not possible to include a null character in data
23 generated via the command-line versions of PGP. On EBCDIC systems we
24 have to hardcode in the character codes since the pre-generated data
25 came from an ASCII system */
26
27 #if defined( __MVS__ ) || defined( __VMCMS__ )
28 #define ENVELOPE_TESTDATA ( ( BYTE * ) "\x53\x6F\x6D\x65\x20\x74\x65\x73\x74\x20\x64\x61\x74\x61" )
29 #define ENVELOPE_PGP_TESTDATA ( ( BYTE * ) "\x53\x6F\x6D\x65\x20\x74\x65\x73\x74\x20\x64\x61\x74\x61\x2E" )
30 #define ENVELOPE_COMPRESSEDDATA "\x2F\x2A\x20\x54\x68\x69\x73\x20\x69\x73\x20\x61\x20\x6C\x6F\x77\x65\x73\x74\x2D"
31 #else
32 #define ENVELOPE_TESTDATA ( ( BYTE * ) "Some test data" )
33 #define ENVELOPE_PGP_TESTDATA ( ( BYTE * ) "Some test data." )
34 #define ENVELOPE_COMPRESSEDDATA "/* This is a lowest-"
35 #endif /* EBCDIC systems */
36 #define ENVELOPE_TESTDATA_SIZE 15
37 #define ENVELOPE_COMPRESSEDDATA_SIZE 20
38
39 /* External flags which indicate that the key read/update routines worked OK.
40 This is set by earlier self-test code, if it isn't set some of the tests
41 are disabled */
42
43 extern int keyReadOK, doubleCertOK;
44
45 #if defined( TEST_ENVELOPE ) || defined( TEST_SESSION ) /* For TSP enveloping */
46
47 /****************************************************************************
48 * *
49 * Utility Routines *
50 * *
51 ****************************************************************************/
52
53 /* The general-purpose buffer used for enveloping. We use a fixed buffer
54 if possible to save having to add huge amounts of allocation/deallocation
55 code */
56
57 BYTE FAR_BSS globalBuffer[ BUFFER_SIZE ];
58
59 /* Determine the size of a file. If there's a problem, we return the
60 default buffer size, which will cause a failure further up the chain
61 where the error can be reported better */
62
getFileSize(const char * fileName)63 static int getFileSize( const char *fileName )
64 {
65 FILE *filePtr;
66 long size;
67
68 if( ( filePtr = fopen( fileName, "rb" ) ) == NULL )
69 return( BUFFER_SIZE );
70 fseek( filePtr, 0L, SEEK_END );
71 size = ftell( filePtr );
72 fclose( filePtr );
73 if( size > INT_MAX )
74 return( BUFFER_SIZE );
75
76 return( ( int ) size );
77 }
78
79 /* Read test data from a file */
80
readFileFromTemplate(const C_STR fileTemplate,const int count,const char * description,BYTE * buffer,const int bufSize)81 static int readFileFromTemplate( const C_STR fileTemplate, const int count,
82 const char *description, BYTE *buffer,
83 const int bufSize )
84 {
85 BYTE fileName[ BUFFER_SIZE ];
86
87 filenameFromTemplate( fileName, fileTemplate, count );
88 return( readFileData( fileName, description, buffer, bufSize, 32,
89 FALSE ) );
90 }
91
92 /* Common routines to create an envelope, add enveloping information, push
93 data, pop data, and destroy an envelope */
94
createEnvelope(CRYPT_ENVELOPE * envelope,const CRYPT_FORMAT_TYPE formatType)95 static int createEnvelope( CRYPT_ENVELOPE *envelope,
96 const CRYPT_FORMAT_TYPE formatType )
97 {
98 int status;
99
100 /* Create the envelope */
101 status = cryptCreateEnvelope( envelope, CRYPT_UNUSED, formatType );
102 if( cryptStatusError( status ) )
103 {
104 printf( "cryptCreateEnvelope() failed with error code %d, line %d.\n",
105 status, __LINE__ );
106 return( FALSE );
107 }
108
109 return( TRUE );
110 }
111
createDeenvelope(CRYPT_ENVELOPE * envelope)112 static int createDeenvelope( CRYPT_ENVELOPE *envelope )
113 {
114 int status;
115
116 /* Create the envelope */
117 status = cryptCreateEnvelope( envelope, CRYPT_UNUSED, CRYPT_FORMAT_AUTO );
118 if( cryptStatusError( status ) )
119 {
120 printf( "cryptCreateEnvelope() for de-enveloping failed with error "
121 "code %d, line %d.\n", status, __LINE__ );
122 return( FALSE );
123 }
124
125 return( TRUE );
126 }
127
addEnvInfoString(const CRYPT_ENVELOPE envelope,const CRYPT_ATTRIBUTE_TYPE type,const void * envInfo,const int envInfoLen)128 static int addEnvInfoString( const CRYPT_ENVELOPE envelope,
129 const CRYPT_ATTRIBUTE_TYPE type,
130 const void *envInfo, const int envInfoLen )
131 {
132 int status;
133
134 status = cryptSetAttributeString( envelope, type, envInfo, envInfoLen );
135 if( cryptStatusError( status ) )
136 {
137 printf( "cryptSetAttributeString() failed with error code %d, "
138 "line %d.\n", status, __LINE__ );
139 return( FALSE );
140 }
141
142 return( TRUE );
143 }
144
addEnvInfoNumeric(const CRYPT_ENVELOPE envelope,const CRYPT_ATTRIBUTE_TYPE type,const int envInfo)145 static int addEnvInfoNumeric( const CRYPT_ENVELOPE envelope,
146 const CRYPT_ATTRIBUTE_TYPE type,
147 const int envInfo )
148 {
149 int status;
150
151 status = cryptSetAttribute( envelope, type, envInfo );
152 if( cryptStatusError( status ) )
153 {
154 fprintf( outputStream, "cryptSetAttribute() of %d failed with error "
155 "code %d, line %d.\n", type, status, __LINE__ );
156 return( FALSE );
157 }
158
159 return( TRUE );
160 }
161
processEnvelopeResource(const CRYPT_ENVELOPE envelope,const void * stringEnvInfo,const int numericEnvInfo,BOOLEAN * isRestartable)162 static int processEnvelopeResource( const CRYPT_ENVELOPE envelope,
163 const void *stringEnvInfo,
164 const int numericEnvInfo,
165 BOOLEAN *isRestartable )
166 {
167 BOOLEAN isWrongKey = FALSE, exitLoop = FALSE;
168 int cryptEnvInfo, cryptAlgo, keySize DUMMY_INIT;
169 int integrityLevel, iteration = 0, status;
170
171 /* Args are either NULL, a handle, or { data, length } */
172 assert( ( stringEnvInfo == NULL && numericEnvInfo == 0 ) || \
173 ( stringEnvInfo == NULL && numericEnvInfo != 0 ) || \
174 ( stringEnvInfo != NULL && numericEnvInfo >= 1 ) );
175
176 /* Clear return value */
177 *isRestartable = FALSE;
178
179 /* Add the appropriate enveloping information that we need to
180 continue */
181 status = cryptSetAttribute( envelope, CRYPT_ATTRIBUTE_CURRENT_GROUP,
182 CRYPT_CURSOR_FIRST );
183 if( cryptStatusError( status ) )
184 {
185 printf( "Attempt to move cursor to start of list failed with error "
186 "code %d, line %d.\n", status, __LINE__ );
187 return( status );
188 }
189 do
190 {
191 C_CHR label[ CRYPT_MAX_TEXTSIZE + 1 ];
192 int labelLength;
193
194 status = cryptGetAttribute( envelope, CRYPT_ATTRIBUTE_CURRENT,
195 &cryptEnvInfo );
196 if( cryptStatusError( status ) )
197 {
198 printf( "Attempt to read current group failed with error code "
199 "%d, line %d.\n", status, __LINE__ );
200 return( status );
201 }
202 iteration++;
203
204 switch( cryptEnvInfo )
205 {
206 case CRYPT_ATTRIBUTE_NONE:
207 /* The required information was supplied via other means (in
208 practice this means there's a crypto device available and
209 that was used for the decrypt), there's nothing left to
210 do */
211 puts( "(Decryption key was recovered using crypto device or "
212 "non-password-protected\n private key)." );
213 break;
214
215 case CRYPT_ENVINFO_PRIVATEKEY:
216 /* If there's no decryption password present, the private
217 key must be passed in directly */
218 if( stringEnvInfo == NULL )
219 {
220 status = cryptSetAttribute( envelope,
221 CRYPT_ENVINFO_PRIVATEKEY,
222 numericEnvInfo );
223 if( cryptStatusError( status ) )
224 {
225 if( status != CRYPT_ERROR_WRONGKEY )
226 {
227 printf( "Attempt to add private key failed "
228 "with error code %d, line %d.\n",
229 status, __LINE__ );
230 return( status );
231 }
232 printf( "Attempt to add private key for attribute "
233 "#%d failed with CRYPT_ERROR_WRONGKEY,\n"
234 " trying for subsequent attributes.\n",
235 iteration );
236 isWrongKey = TRUE;
237 }
238 else
239 {
240 if( isWrongKey )
241 {
242 isWrongKey = FALSE;
243 printf( "Decryption succeeded for attribute "
244 "#%d.\n", iteration );
245 }
246 exitLoop = TRUE;
247 }
248 *isRestartable = TRUE;
249 break;
250 }
251
252 /* A private-key keyset is present in the envelope, we need
253 a password to decrypt the key */
254 status = cryptGetAttributeString( envelope,
255 CRYPT_ENVINFO_PRIVATEKEY_LABEL,
256 label, &labelLength );
257 if( cryptStatusError( status ) )
258 {
259 printf( "Private key label read failed with error code "
260 "%d, line %d.\n", status, __LINE__ );
261 return( status );
262 }
263 #ifdef UNICODE_STRINGS
264 label[ labelLength / sizeof( wchar_t ) ] = '\0';
265 printf( "Need password to decrypt private key '%S'.\n",
266 label );
267 #else
268 label[ labelLength ] = '\0';
269 fprintf( outputStream, "Need password to decrypt private key "
270 "'%s'.\n", label );
271 #endif /* UNICODE_STRINGS */
272 if( !addEnvInfoString( envelope, CRYPT_ENVINFO_PASSWORD,
273 stringEnvInfo, numericEnvInfo ) )
274 return( SENTINEL );
275 *isRestartable = TRUE;
276 break;
277
278 case CRYPT_ENVINFO_PASSWORD:
279 fputs( "Need user password.", outputStream );
280 assert( stringEnvInfo != NULL ); /* For static analysers */
281 status = cryptSetAttributeString( envelope,
282 CRYPT_ENVINFO_PASSWORD, stringEnvInfo,
283 numericEnvInfo );
284 if( cryptStatusError( status ) )
285 {
286 if( status != CRYPT_ERROR_WRONGKEY )
287 {
288 printf( "Attempt to add password failed with error "
289 "code %d, line %d.\n", status, __LINE__ );
290 return( status );
291 }
292 printf( "Attempt to add password for attribute #%d "
293 "failed with CRYPT_ERROR_WRONGKEY, trying for "
294 "subsequent attributes.\n", iteration );
295 isWrongKey = TRUE;
296 }
297 else
298 {
299 if( isWrongKey )
300 {
301 isWrongKey = FALSE;
302 printf( "Decryption succeeded for attribute "
303 "#%d.\n", iteration );
304 }
305 exitLoop = TRUE;
306 }
307 *isRestartable = TRUE;
308 break;
309
310 case CRYPT_ENVINFO_SESSIONKEY:
311 fputs( "Need session key.", outputStream );
312 if( !addEnvInfoNumeric( envelope, CRYPT_ENVINFO_SESSIONKEY,
313 numericEnvInfo ) )
314 return( SENTINEL );
315 *isRestartable = TRUE;
316 break;
317
318 case CRYPT_ENVINFO_KEY:
319 fputs( "Need conventional encryption key.", outputStream );
320 if( !addEnvInfoNumeric( envelope, CRYPT_ENVINFO_KEY,
321 numericEnvInfo ) )
322 return( SENTINEL );
323 *isRestartable = TRUE;
324 break;
325
326 case CRYPT_ENVINFO_SIGNATURE:
327 /* If we've processed the entire data block in one go, we
328 may end up with only signature information available, in
329 which case we defer processing them until after we've
330 finished with the deenveloped data */
331 break;
332
333 default:
334 printf( "Need unknown enveloping information type %d.\n",
335 cryptEnvInfo );
336 return( SENTINEL );
337 }
338 }
339 while( !exitLoop && \
340 cryptSetAttribute( envelope, CRYPT_ATTRIBUTE_CURRENT_GROUP,
341 CRYPT_CURSOR_NEXT ) == CRYPT_OK );
342
343 /* If we couldn't find a usable decryption key, we can't go any
344 further */
345 if( isWrongKey )
346 {
347 printf( "Couldn't find key capable of decrypting enveloped data, "
348 "line %d.\n", __LINE__ );
349 return( FALSE );
350 }
351
352 /* Check whether there's any integrity protection present */
353 status = cryptGetAttribute( envelope, CRYPT_ENVINFO_INTEGRITY,
354 &integrityLevel );
355 if( cryptStatusError( status ) )
356 {
357 printf( "Couldn't query integrity protection used in envelope, "
358 "status %d, line %d.\n", status, __LINE__ );
359 return( status );
360 }
361 if( integrityLevel > CRYPT_INTEGRITY_NONE )
362 {
363 /* Display the integrity level. For PGP it's not really a MAC but
364 a sort-of-keyed encrypted hash, but we call it a MAC to keep
365 things simple */
366 fprintf( outputStream, "Data is integrity-protected using %s "
367 "authentication.\n",
368 ( integrityLevel == CRYPT_INTEGRITY_MACONLY ) ? \
369 "MAC" : \
370 ( integrityLevel == CRYPT_INTEGRITY_FULL ) ? \
371 "MAC+encrypt" : "unknown" );
372 }
373
374 /* If we're not using encryption, we're done */
375 if( cryptEnvInfo != CRYPT_ATTRIBUTE_NONE && \
376 cryptEnvInfo != CRYPT_ENVINFO_PRIVATEKEY && \
377 cryptEnvInfo != CRYPT_ENVINFO_PASSWORD )
378 return( CRYPT_OK );
379 if( integrityLevel == CRYPT_INTEGRITY_MACONLY )
380 return( CRYPT_OK );
381
382 /* If we're using some form of encrypted enveloping, report the
383 algorithm and keysize used */
384 status = cryptGetAttribute( envelope, CRYPT_CTXINFO_ALGO, &cryptAlgo );
385 if( cryptStatusOK( status ) )
386 status = cryptGetAttribute( envelope, CRYPT_CTXINFO_KEYSIZE,
387 &keySize );
388 if( cryptStatusError( status ) )
389 {
390 printf( "Couldn't query encryption algorithm and keysize used in "
391 "envelope, status %d, line %d.\n", status, __LINE__ );
392 return( status );
393 }
394 fprintf( outputStream, "Data is protected using algorithm %d with %d "
395 "bit key.\n", cryptAlgo, keySize * 8 );
396
397 return( CRYPT_OK );
398 }
399
pushData(const CRYPT_ENVELOPE envelope,const BYTE * buffer,const int length,const void * stringEnvInfo,const int numericEnvInfo)400 static int pushData( const CRYPT_ENVELOPE envelope, const BYTE *buffer,
401 const int length, const void *stringEnvInfo,
402 const int numericEnvInfo )
403 {
404 int bytesIn, contentType, status;
405
406 /* Args are either NULL, a handle, or { data, length } */
407 assert( ( stringEnvInfo == NULL && numericEnvInfo == 0 ) || \
408 ( stringEnvInfo == NULL && numericEnvInfo != 0 ) || \
409 ( stringEnvInfo != NULL && numericEnvInfo >= 1 ) );
410
411 /* Push in the data */
412 status = cryptPushData( envelope, buffer, length, &bytesIn );
413 if( status == CRYPT_ENVELOPE_RESOURCE )
414 {
415 BOOLEAN isRestartable = FALSE;
416
417 /* Process the required de-enveloping resource */
418 status = processEnvelopeResource( envelope, stringEnvInfo,
419 numericEnvInfo, &isRestartable );
420 if( cryptStatusError( status ) )
421 return( status );
422
423 /* If we only got some of the data in due to the envelope stopping to
424 ask us for a decryption resource, push in the rest */
425 if( bytesIn < length && isRestartable )
426 {
427 const int initialBytesIn = bytesIn;
428
429 status = cryptPushData( envelope, buffer + initialBytesIn,
430 length - initialBytesIn, &bytesIn );
431 if( cryptStatusError( status ) )
432 {
433 printf( "cryptPushData() for remaining data failed with "
434 "error code %d, line %d.\n", status, __LINE__ );
435 return( status );
436 }
437 bytesIn += initialBytesIn;
438 }
439 }
440 else
441 {
442 if( cryptStatusError( status ) )
443 {
444 printExtError( envelope, "cryptPushData()", status, __LINE__ );
445 return( status );
446 }
447 }
448 if( bytesIn < length )
449 {
450 BYTE tempBuffer[ 8192 ];
451 int bytesIn2, bytesOut;
452
453 /* In the case of very large data quantities we may run out of
454 envelope buffer space during processing so we have to push the
455 remainder a second time. Removing some of the data destroys
456 the ability to compare the popped data with the input data later
457 on, but this is only done for the known self-test data and not
458 for import of arbitrary external data quantities */
459 printf( "(Ran out of input buffer data space, popping %d bytes to "
460 "make room).\n", 8192 );
461 status = cryptPopData( envelope, tempBuffer, 8192, &bytesOut );
462 if( cryptStatusError( status ) )
463 {
464 printf( "cryptPopData() to make way for remaining data failed "
465 "with error code %d, line %d.\n", status, __LINE__ );
466 return( status );
467 }
468 status = cryptPushData( envelope, buffer + bytesIn,
469 length - bytesIn, &bytesIn2 );
470 if( cryptStatusError( status ) )
471 {
472 printExtError( envelope, "cryptPushData() of remaining data",
473 status, __LINE__ );
474 return( status );
475 }
476 bytesIn += bytesIn2;
477 }
478 if( bytesIn != length )
479 {
480 printf( "cryptPushData() only copied %d of %d bytes, line %d.\n",
481 bytesIn, length, __LINE__ );
482 return( SENTINEL );
483 }
484
485 /* Flush the data */
486 status = cryptFlushData( envelope );
487 if( cryptStatusError( status ) && status != CRYPT_ERROR_COMPLETE )
488 {
489 printExtError( envelope, "cryptFlushData()", status, __LINE__ );
490 return( status );
491 }
492
493 /* Now that we've finished processing the data, report the inner content
494 type. We can't do in until this stage because some enveloping format
495 types encrypt the inner content type with the payload, so we can't
496 tell what it is until we've decrypted the payload */
497 status = cryptGetAttribute( envelope, CRYPT_ENVINFO_CONTENTTYPE,
498 &contentType );
499 if( cryptStatusError( status ) )
500 {
501 int value;
502
503 /* A detached signature doesn't have any content to an inability to
504 determine the content type isn't a failure */
505 status = cryptGetAttribute( envelope, CRYPT_ENVINFO_DETACHEDSIGNATURE,
506 &value );
507 if( cryptStatusOK( status ) && value == TRUE )
508 {
509 puts( "(Data is from a detached signature, couldn't determine "
510 "content type)." );
511 return( bytesIn );
512 }
513 printf( "Couldn't query content type in envelope, status %d, "
514 "line %d.\n", status, __LINE__ );
515 return( status );
516 }
517 if( contentType != CRYPT_CONTENT_DATA )
518 fprintf( outputStream, "Nested content type = %d.\n", contentType );
519
520 return( bytesIn );
521 }
522
popData(CRYPT_ENVELOPE envelope,BYTE * buffer,int bufferSize)523 static int popData( CRYPT_ENVELOPE envelope, BYTE *buffer, int bufferSize )
524 {
525 int status, bytesOut;
526
527 status = cryptPopData( envelope, buffer, bufferSize, &bytesOut );
528 if( cryptStatusError( status ) )
529 {
530 printExtError( envelope, "cryptPopData()", status, __LINE__ );
531 return( status );
532 }
533
534 return( bytesOut );
535 }
536
destroyEnvelope(CRYPT_ENVELOPE envelope)537 static int destroyEnvelope( CRYPT_ENVELOPE envelope )
538 {
539 int status;
540
541 /* Destroy the envelope */
542 status = cryptDestroyEnvelope( envelope );
543 if( cryptStatusError( status ) )
544 {
545 printf( "cryptDestroyEnvelope() failed with error code %d, line %d.\n",
546 status, __LINE__ );
547 return( FALSE );
548 }
549
550 return( TRUE );
551 }
552
553 /****************************************************************************
554 * *
555 * Data Enveloping Routines *
556 * *
557 ****************************************************************************/
558
559 /* Test raw data enveloping */
560
envelopeData(const char * dumpFileName,const BOOLEAN useDatasize,const int bufferSize,const CRYPT_FORMAT_TYPE formatType)561 static int envelopeData( const char *dumpFileName,
562 const BOOLEAN useDatasize,
563 const int bufferSize,
564 const CRYPT_FORMAT_TYPE formatType )
565 {
566 CRYPT_ENVELOPE cryptEnvelope;
567 BYTE *inBufPtr, *outBufPtr = globalBuffer;
568 int length, bufSize, count;
569
570 switch( bufferSize )
571 {
572 case 0:
573 printf( "Testing %splain data enveloping%s...\n",
574 ( formatType == CRYPT_FORMAT_PGP ) ? "PGP " : "",
575 ( useDatasize && ( formatType != CRYPT_FORMAT_PGP ) ) ? \
576 " with datasize hint" : "" );
577 length = ENVELOPE_TESTDATA_SIZE;
578 inBufPtr = ENVELOPE_TESTDATA;
579 break;
580
581 case 1:
582 printf( "Testing %splain data enveloping of intermediate-size data...\n",
583 ( formatType == CRYPT_FORMAT_PGP ) ? "PGP " : "" );
584 length = 512;
585 inBufPtr = globalBuffer;
586 for( count = 0; count < length; count++ )
587 inBufPtr[ count ] = count & 0xFF;
588 break;
589
590 case 2:
591 printf( "Testing %senveloping of large data quantity...\n",
592 ( formatType == CRYPT_FORMAT_PGP ) ? "PGP " : "" );
593
594 /* Allocate a large buffer and fill it with a known value */
595 length = ( INT_MAX <= 32768L ) ? 16384 : 1048576;
596 if( ( inBufPtr = malloc( length + 128 ) ) == NULL )
597 {
598 printf( "Couldn't allocate buffer of %d bytes, skipping large "
599 "buffer enveloping test.\n", length );
600 return( TRUE );
601 }
602 outBufPtr = inBufPtr;
603 for( count = 0; count < length; count++ )
604 inBufPtr[ count ] = count & 0xFF;
605 break;
606
607 default:
608 return( FALSE );
609 }
610 bufSize = length + 128;
611
612 /* Create the envelope, push in the data, pop the enveloped result, and
613 destroy the envelope */
614 if( !createEnvelope( &cryptEnvelope, formatType ) )
615 {
616 if( bufferSize > 1 )
617 free( inBufPtr );
618 return( FALSE );
619 }
620 if( useDatasize )
621 cryptSetAttribute( cryptEnvelope, CRYPT_ENVINFO_DATASIZE, length );
622 if( bufferSize > 1 )
623 cryptSetAttribute( cryptEnvelope, CRYPT_ATTRIBUTE_BUFFERSIZE,
624 length + 1024 );
625 count = pushData( cryptEnvelope, inBufPtr, length, NULL, 0 );
626 if( cryptStatusError( count ) )
627 {
628 if( bufferSize > 1 )
629 free( inBufPtr );
630 return( FALSE );
631 }
632 count = popData( cryptEnvelope, outBufPtr, bufSize );
633 if( cryptStatusError( count ) )
634 {
635 if( bufferSize > 1 )
636 free( inBufPtr );
637 return( FALSE );
638 }
639 if( !destroyEnvelope( cryptEnvelope ) )
640 {
641 if( bufferSize > 1 )
642 free( inBufPtr );
643 return( FALSE );
644 }
645 if( bufferSize == 0 && \
646 count != length + ( ( formatType == CRYPT_FORMAT_PGP ) ? 8 : \
647 useDatasize ? 17 : 25 ) )
648 {
649 printf( "Enveloped data length %d, should be %d, line %d.\n",
650 count, length + 25, __LINE__ );
651 if( bufferSize > 1 )
652 free( inBufPtr );
653 return( FALSE );
654 }
655
656 /* Tell them what happened */
657 printf( "Enveloped data has size %d bytes.\n", count );
658 if( bufferSize < 2 )
659 debugDump( dumpFileName, outBufPtr, count );
660
661 /* Create the envelope, push in the data, pop the de-enveloped result,
662 and destroy the envelope */
663 if( !createDeenvelope( &cryptEnvelope ) )
664 {
665 if( bufferSize > 1 )
666 free( inBufPtr );
667 return( FALSE );
668 }
669 if( bufferSize > 1 )
670 cryptSetAttribute( cryptEnvelope, CRYPT_ATTRIBUTE_BUFFERSIZE,
671 length + 1024 );
672 count = pushData( cryptEnvelope, outBufPtr, count, NULL, 0 );
673 if( cryptStatusError( count ) )
674 {
675 if( bufferSize > 1 )
676 free( inBufPtr );
677 return( FALSE );
678 }
679 count = popData( cryptEnvelope, outBufPtr, bufSize );
680 if( cryptStatusError( count ) )
681 {
682 if( bufferSize > 1 )
683 free( inBufPtr );
684 return( FALSE );
685 }
686 if( !destroyEnvelope( cryptEnvelope ) )
687 {
688 if( bufferSize > 1 )
689 free( inBufPtr );
690 return( FALSE );
691 }
692
693 /* Make sure that the result matches what we pushed */
694 if( count != length )
695 {
696 puts( "De-enveloped data length != original length." );
697 if( bufferSize > 1 )
698 free( inBufPtr );
699 return( FALSE );
700 }
701 if( bufferSize > 0 )
702 {
703 int i;
704
705 for( i = 0; i < length; i++ )
706 if( outBufPtr[ i ] != ( i & 0xFF ) )
707 {
708 printf( "De-enveloped data != original data at byte %d, "
709 "line %d.\n", i, __LINE__ );
710 if( bufferSize > 1 )
711 free( inBufPtr );
712 return( FALSE );
713 }
714 }
715 else
716 {
717 if( !compareData( ENVELOPE_TESTDATA, length, outBufPtr, length ) )
718 {
719 if( bufferSize > 1 )
720 free( inBufPtr );
721 return( FALSE );
722 }
723 }
724
725 /* Clean up */
726 if( bufferSize > 1 )
727 free( inBufPtr );
728 puts( "Enveloping of plain data succeeded.\n" );
729 return( TRUE );
730 }
731
testEnvelopeData(void)732 int testEnvelopeData( void )
733 {
734 if( !envelopeData( "env_datn", FALSE, 0, CRYPT_FORMAT_CRYPTLIB ) )
735 return( FALSE ); /* Indefinite-length */
736 if( !envelopeData( "env_dat", TRUE, 0, CRYPT_FORMAT_CRYPTLIB ) )
737 return( FALSE ); /* Datasize */
738 if( !envelopeData( "env_dat.pgp", TRUE, 0, CRYPT_FORMAT_PGP ) )
739 return( FALSE ); /* PGP format */
740 return( envelopeData( "env_datl.pgp", TRUE, 1, CRYPT_FORMAT_PGP ) );
741 } /* PGP format, longer data */
742
testEnvelopeDataLargeBuffer(void)743 int testEnvelopeDataLargeBuffer( void )
744 {
745 if( !envelopeData( NULL, TRUE, 2, CRYPT_FORMAT_CRYPTLIB ) )
746 return( FALSE ); /* Datasize, large buffer */
747 return( envelopeData( NULL, TRUE, 2, CRYPT_FORMAT_PGP ) );
748 } /* Large buffer, PGP format */
749
750 /* Test compressed enveloping */
751
envelopeDecompress(BYTE * buffer,const int bufSize,const int length)752 static int envelopeDecompress( BYTE *buffer, const int bufSize,
753 const int length )
754 {
755 CRYPT_ENVELOPE cryptEnvelope;
756 BYTE smallBuffer[ 128 ];
757 int count, zeroCount;
758
759 /* Create the envelope, push in the data, and pop the de-enveloped
760 result */
761 if( !createDeenvelope( &cryptEnvelope ) )
762 return( FALSE );
763 count = pushData( cryptEnvelope, buffer, length, NULL, 0 );
764 if( cryptStatusError( count ) )
765 return( FALSE );
766 count = popData( cryptEnvelope, buffer, bufSize );
767 if( cryptStatusError( count ) )
768 {
769 #ifdef __hpux
770 if( count == -1 )
771 {
772 puts( "Older HPUX compilers break zlib, to remedy this you can "
773 "either get a better\ncompiler/OS or grab a debugger and "
774 "try to figure out what HPUX is doing to\nzlib. To "
775 "continue the self-tests, comment out the call to\n"
776 "testEnvelopeCompress() and rebuild." );
777 }
778 #endif /* __hpux */
779 return( FALSE );
780 }
781
782 /* See what happens when we try and pop out more data. This test is done
783 because some compressed-data formats don't indicate the end of the
784 data properly, and we need to make sure that the de-enveloping code
785 handles this correctly. This also tests for correct handling of
786 oddball OOB data tacked onto the end of the payload, like PGP's
787 MDCs */
788 zeroCount = popData( cryptEnvelope, smallBuffer, 128 );
789 if( zeroCount != 0 )
790 {
791 printf( "Attempt to pop more data after end-of-data had been "
792 "reached succeeded, the\nenvelope should have reported 0 "
793 "bytes available rather than %d.\n", zeroCount );
794 return( FALSE );
795 }
796
797 /* Clean up */
798 if( !destroyEnvelope( cryptEnvelope ) )
799 return( FALSE );
800 return( count );
801 }
802
envelopeCompress(const char * dumpFileName,const BOOLEAN useDatasize,const CRYPT_FORMAT_TYPE formatType)803 static int envelopeCompress( const char *dumpFileName,
804 const BOOLEAN useDatasize,
805 const CRYPT_FORMAT_TYPE formatType )
806 {
807 CRYPT_ENVELOPE cryptEnvelope;
808 FILE *inFile;
809 BYTE *buffer, *envelopedBuffer;
810 int dataCount = 0, count, status;
811
812 printf( "Testing %scompressed data enveloping%s...\n",
813 ( formatType == CRYPT_FORMAT_PGP ) ? "PGP " : "",
814 useDatasize ? " with datasize hint" : "" );
815
816 /* Since this needs a nontrivial amount of data for the compression, we
817 read it from an external file into dynamically-allocated buffers */
818 if( ( ( buffer = malloc( FILEBUFFER_SIZE ) ) == NULL ) || \
819 ( ( envelopedBuffer = malloc( FILEBUFFER_SIZE ) ) == NULL ) )
820 {
821 if( buffer != NULL )
822 free( buffer );
823 puts( "Couldn't allocate test buffers." );
824 return( FALSE );
825 }
826 inFile = fopen( convertFileName( COMPRESS_FILE ), "rb" );
827 if( inFile != NULL )
828 {
829 dataCount = fread( buffer, 1, FILEBUFFER_SIZE, inFile );
830 fclose( inFile );
831 assert( dataCount < FILEBUFFER_SIZE );
832 }
833 if( dataCount < 1000 || dataCount == FILEBUFFER_SIZE )
834 {
835 free( buffer );
836 free( envelopedBuffer );
837 puts( "Couldn't read test file for compression." );
838 return( FALSE );
839 }
840
841 /* Create the envelope, push in the data, pop the enveloped result, and
842 destroy the envelope */
843 if( !createEnvelope( &cryptEnvelope, formatType ) )
844 {
845 free( buffer );
846 free( envelopedBuffer );
847 return( FALSE );
848 }
849 status = cryptSetAttribute( cryptEnvelope, CRYPT_ENVINFO_COMPRESSION,
850 CRYPT_UNUSED );
851 if( cryptStatusError( status ) )
852 {
853 free( buffer );
854 free( envelopedBuffer );
855 printf( "Attempt to enable compression failed, status = %d, "
856 "line %d.\n", status, __LINE__ );
857 return( FALSE );
858 }
859 if( useDatasize )
860 cryptSetAttribute( cryptEnvelope, CRYPT_ENVINFO_DATASIZE, dataCount );
861 count = pushData( cryptEnvelope, buffer, dataCount, NULL, 0 );
862 if( cryptStatusError( count ) )
863 {
864 free( buffer );
865 free( envelopedBuffer );
866 return( FALSE );
867 }
868 count = popData( cryptEnvelope, envelopedBuffer, FILEBUFFER_SIZE );
869 if( count > dataCount - 1000 )
870 {
871 printf( "Compression of data failed, %d bytes in -> %d bytes out, "
872 "line %d.\n", dataCount, count, __LINE__ );
873 free( buffer );
874 free( envelopedBuffer );
875 return( FALSE );
876 }
877 if( cryptStatusError( count ) || \
878 !destroyEnvelope( cryptEnvelope ) )
879 {
880 free( buffer );
881 free( envelopedBuffer );
882 return( FALSE );
883 }
884
885 /* Tell them what happened */
886 printf( "Enveloped data has size %d bytes.\n", count );
887 debugDump( dumpFileName, envelopedBuffer, count );
888
889 /* De-envelope the data and make sure that the result matches what we
890 pushed */
891 count = envelopeDecompress( envelopedBuffer, FILEBUFFER_SIZE, count );
892 if( count <= 0 )
893 {
894 free( buffer );
895 free( envelopedBuffer );
896 return( FALSE );
897 }
898 if( !compareData( buffer, dataCount, envelopedBuffer, count ) )
899 {
900 free( buffer );
901 free( envelopedBuffer );
902 return( FALSE );
903 }
904
905 /* Clean up */
906 puts( "Enveloping of compressed data succeeded.\n" );
907 free( buffer );
908 free( envelopedBuffer );
909 return( TRUE );
910 }
911
testEnvelopeCompress(void)912 int testEnvelopeCompress( void )
913 {
914 /* In practice these two produce identical output since we always have to
915 use the indefinite-length encoding internally because we don't know in
916 advance how large the compressed data will be */
917 if( !envelopeCompress( "env_cprn", FALSE, CRYPT_FORMAT_CRYPTLIB ) )
918 return( FALSE ); /* Indefinite length */
919 if( !envelopeCompress( "env_cpr", TRUE, CRYPT_FORMAT_CRYPTLIB ) )
920 return( FALSE ); /* Datasize */
921 return( envelopeCompress( "env_cpr.pgp", TRUE, CRYPT_FORMAT_PGP ) );
922 } /* PGP format */
923
924 /****************************************************************************
925 * *
926 * Encrypted Enveloping Routines *
927 * *
928 ****************************************************************************/
929
930 /* Test encrypted enveloping with a raw session key */
931
envelopeSessionCrypt(const char * dumpFileName,const BOOLEAN useDatasize,const BOOLEAN useStreamCipher,const BOOLEAN useLargeBuffer,const CRYPT_FORMAT_TYPE formatType)932 static int envelopeSessionCrypt( const char *dumpFileName,
933 const BOOLEAN useDatasize,
934 const BOOLEAN useStreamCipher,
935 const BOOLEAN useLargeBuffer,
936 const CRYPT_FORMAT_TYPE formatType )
937 {
938 CRYPT_ENVELOPE cryptEnvelope;
939 CRYPT_CONTEXT cryptContext;
940 CRYPT_ALGO_TYPE cryptAlgo = ( formatType == CRYPT_FORMAT_PGP ) ? \
941 selectCipher( CRYPT_ALGO_IDEA ) : \
942 selectCipher( CRYPT_ALGO_AES );
943 BYTE *inBufPtr = ENVELOPE_TESTDATA, *outBufPtr = globalBuffer;
944 #if defined( __MSDOS16__ ) || defined( __WIN16__ )
945 const int length = useLargeBuffer ? 16384 : ENVELOPE_TESTDATA_SIZE;
946 #else
947 const int length = useLargeBuffer ? 1048576L : ENVELOPE_TESTDATA_SIZE;
948 #endif /* 16- vs.32-bit systems */
949 const int bufSize = length + 128;
950 int count, status;
951
952 if( useLargeBuffer )
953 {
954 int i;
955
956 printf( "Testing %sraw-session-key encrypted enveloping of large "
957 "data quantity...\n",
958 ( formatType == CRYPT_FORMAT_PGP ) ? "PGP " : "" );
959
960 /* Allocate a large buffer and fill it with a known value */
961 if( ( inBufPtr = malloc( bufSize ) ) == NULL )
962 {
963 printf( "Couldn't allocate buffer of %d bytes, skipping large "
964 "buffer enveloping test.\n", length );
965 return( TRUE );
966 }
967 outBufPtr = inBufPtr;
968 for( i = 0; i < length; i++ )
969 inBufPtr[ i ] = i & 0xFF;
970 }
971 else
972 {
973 printf( "Testing %sraw-session-key encrypted enveloping%s...\n",
974 ( formatType == CRYPT_FORMAT_PGP ) ? "PGP " : "",
975 ( useStreamCipher ) ? " with stream cipher" : \
976 ( useDatasize && ( formatType != CRYPT_FORMAT_PGP ) ) ? \
977 " with datasize hint" : "" );
978 }
979
980 if( formatType != CRYPT_FORMAT_PGP )
981 {
982 /* Create the session key context. We don't check for errors here
983 since this code will already have been tested earlier */
984 status = cryptCreateContext( &cryptContext, CRYPT_UNUSED,
985 cryptAlgo );
986 if( cryptStatusError( status ) )
987 return( FALSE );
988 }
989 else
990 {
991 /* PGP only allows a limited subset of algorithms and modes, in
992 addition we have to specifically check that IDEA is available
993 since it's possible to build cryptlib without IDEA support */
994 if( cryptAlgo != CRYPT_ALGO_IDEA )
995 {
996 puts( "Can't test PGP enveloping because the IDEA algorithm "
997 "isn't available in this\nbuild of cryptlib.\n" );
998 return( TRUE );
999 }
1000 status = cryptCreateContext( &cryptContext, CRYPT_UNUSED,
1001 cryptAlgo );
1002 if( cryptStatusError( status ) )
1003 return( FALSE );
1004 cryptSetAttribute( cryptContext, CRYPT_CTXINFO_MODE,
1005 CRYPT_MODE_CFB );
1006 }
1007 cryptSetAttributeString( cryptContext, CRYPT_CTXINFO_KEY,
1008 "0123456789ABCDEF", 16 );
1009
1010 /* Create the envelope, push in a password and the data, pop the
1011 enveloped result, and destroy the envelope */
1012 if( !createEnvelope( &cryptEnvelope, formatType ) || \
1013 !addEnvInfoNumeric( cryptEnvelope, CRYPT_ENVINFO_SESSIONKEY,
1014 cryptContext ) )
1015 return( FALSE );
1016 if( useDatasize && !useLargeBuffer )
1017 {
1018 /* Test the ability to destroy the context after it's been added
1019 (we replace it with a different context that's used later for
1020 de-enveloping) */
1021 cryptDestroyContext( cryptContext );
1022 status = cryptCreateContext( &cryptContext, CRYPT_UNUSED,
1023 cryptAlgo );
1024 if( cryptStatusError( status ) )
1025 return( FALSE );
1026 cryptSetAttributeString( cryptContext, CRYPT_CTXINFO_KEY,
1027 "0123456789ABCDEF", 16 );
1028
1029 /* As a side-effect, use the new context to test the rejection of
1030 addition of a second session key */
1031 if( addEnvInfoNumeric( cryptEnvelope, CRYPT_ENVINFO_SESSIONKEY,
1032 cryptContext ) )
1033 {
1034 printf( "Addition of duplicate session key succeeded when it "
1035 "should have failed,\nline %d.\n", __LINE__ );
1036 return( FALSE );
1037 }
1038 puts( " (The above message indicates that the test condition was "
1039 "successfully\n checked)." );
1040 }
1041 if( useDatasize )
1042 cryptSetAttribute( cryptEnvelope, CRYPT_ENVINFO_DATASIZE, length );
1043 if( useLargeBuffer )
1044 cryptSetAttribute( cryptEnvelope, CRYPT_ATTRIBUTE_BUFFERSIZE,
1045 length + 1024 );
1046 count = pushData( cryptEnvelope, inBufPtr, length, NULL, 0 );
1047 if( cryptStatusError( count ) )
1048 return( FALSE );
1049 count = popData( cryptEnvelope, outBufPtr, bufSize );
1050 if( cryptStatusError( count ) )
1051 return( FALSE );
1052 if( !destroyEnvelope( cryptEnvelope ) )
1053 return( FALSE );
1054
1055 /* Tell them what happened */
1056 printf( "Enveloped data has size %d bytes.\n", count );
1057 if( !useLargeBuffer )
1058 debugDump( dumpFileName, outBufPtr, count );
1059
1060 /* Create the envelope, push in the data, pop the de-enveloped result,
1061 and destroy the envelope */
1062 if( !createDeenvelope( &cryptEnvelope ) )
1063 return( FALSE );
1064 if( useLargeBuffer )
1065 cryptSetAttribute( cryptEnvelope, CRYPT_ATTRIBUTE_BUFFERSIZE,
1066 length + 1024 );
1067 count = pushData( cryptEnvelope, outBufPtr, count, NULL, cryptContext );
1068 if( cryptStatusError( count ) )
1069 return( FALSE );
1070 count = popData( cryptEnvelope, outBufPtr, bufSize );
1071 if( cryptStatusError( count ) )
1072 return( FALSE );
1073 if( !destroyEnvelope( cryptEnvelope ) )
1074 return( FALSE );
1075
1076 /* Make sure that the result matches what we pushed */
1077 if( count != length )
1078 {
1079 puts( "De-enveloped data length != original length." );
1080 return( FALSE );
1081 }
1082 if( useLargeBuffer )
1083 {
1084 int i;
1085
1086 for( i = 0; i < length; i++ )
1087 if( outBufPtr[ i ] != ( i & 0xFF ) )
1088 {
1089 printf( "De-enveloped data != original data at byte %d, "
1090 "line %d.\n", i, __LINE__ );
1091 return( FALSE );
1092 }
1093 }
1094 else
1095 {
1096 if( !compareData( ENVELOPE_TESTDATA, length, outBufPtr, length ) )
1097 return( FALSE );
1098 }
1099
1100 /* Clean up */
1101 if( useLargeBuffer )
1102 free( inBufPtr );
1103 cryptDestroyContext( cryptContext );
1104 puts( "Enveloping of raw-session-key-encrypted data succeeded.\n" );
1105 return( TRUE );
1106 }
1107
testEnvelopeSessionCrypt(void)1108 int testEnvelopeSessionCrypt( void )
1109 {
1110 if( !envelopeSessionCrypt( "env_sesn", FALSE, FALSE, FALSE, CRYPT_FORMAT_CRYPTLIB ) )
1111 return( FALSE ); /* Indefinite length */
1112 if( !envelopeSessionCrypt( "env_ses", TRUE, FALSE, FALSE, CRYPT_FORMAT_CRYPTLIB ) )
1113 return( FALSE ); /* Datasize */
1114 if( !envelopeSessionCrypt( "env_ses", TRUE, TRUE, FALSE, CRYPT_FORMAT_CRYPTLIB ) )
1115 return( FALSE ); /* Datasize, stream cipher */
1116 #if 0
1117 /* Although in theory PGP supports raw session-key based enveloping, in
1118 practice this key is always (implicitly) derived from a user password,
1119 so the enveloping code doesn't allow the use of raw session keys */
1120 return( envelopeSessionCrypt( "env_ses.pgp", TRUE, FALSE, FALSE, CRYPT_FORMAT_PGP ) );
1121 #endif /* 0 */
1122 return( TRUE );
1123 }
1124
testEnvelopeSessionCryptLargeBuffer(void)1125 int testEnvelopeSessionCryptLargeBuffer( void )
1126 {
1127 return( envelopeSessionCrypt( "env_ses", TRUE, FALSE, TRUE, CRYPT_FORMAT_CRYPTLIB ) );
1128 } /* Datasize, large buffer */
1129
1130 /* Test encrypted enveloping */
1131
envelopeDecrypt(BYTE * buffer,const int length,const CRYPT_CONTEXT cryptContext)1132 static int envelopeDecrypt( BYTE *buffer, const int length,
1133 const CRYPT_CONTEXT cryptContext )
1134 {
1135 CRYPT_ENVELOPE cryptEnvelope;
1136 int count;
1137
1138 /* Create the envelope, push in the data, pop the de-enveloped result,
1139 and destroy the envelope */
1140 if( !createDeenvelope( &cryptEnvelope ) )
1141 return( FALSE );
1142 count = pushData( cryptEnvelope, buffer, length, NULL, cryptContext );
1143 if( cryptStatusError( count ) )
1144 return( FALSE );
1145 count = popData( cryptEnvelope, buffer, BUFFER_SIZE );
1146 if( cryptStatusError( count ) )
1147 return( FALSE );
1148 if( !destroyEnvelope( cryptEnvelope ) )
1149 return( FALSE );
1150 return( count );
1151 }
1152
envelopeCrypt(const char * dumpFileName,const BOOLEAN useDatasize,const CRYPT_FORMAT_TYPE formatType)1153 static int envelopeCrypt( const char *dumpFileName,
1154 const BOOLEAN useDatasize,
1155 const CRYPT_FORMAT_TYPE formatType )
1156 {
1157 CRYPT_CONTEXT cryptContext;
1158 CRYPT_ENVELOPE cryptEnvelope;
1159 int count, status;
1160
1161 printf( "Testing encrypted enveloping%s...\n",
1162 useDatasize ? " with datasize hint" : "" );
1163
1164 /* Create the session key context. We don't check for errors here
1165 since this code will already have been tested earlier */
1166 status = cryptCreateContext( &cryptContext, CRYPT_UNUSED,
1167 CRYPT_ALGO_3DES );
1168 if( cryptStatusError( status ) )
1169 return( FALSE );
1170 cryptSetAttributeString( cryptContext, CRYPT_CTXINFO_KEY,
1171 "0123456789ABCDEF", 16 );
1172
1173 /* Create the envelope, push in a KEK and the data, pop the enveloped
1174 result, and destroy the envelope */
1175 if( !createEnvelope( &cryptEnvelope, formatType ) || \
1176 !addEnvInfoNumeric( cryptEnvelope, CRYPT_ENVINFO_KEY, cryptContext ) )
1177 return( FALSE );
1178 if( useDatasize )
1179 cryptSetAttribute( cryptEnvelope, CRYPT_ENVINFO_DATASIZE,
1180 ENVELOPE_TESTDATA_SIZE );
1181 count = pushData( cryptEnvelope, ENVELOPE_TESTDATA,
1182 ENVELOPE_TESTDATA_SIZE, NULL, 0 );
1183 if( cryptStatusError( count ) )
1184 return( FALSE );
1185 count = popData( cryptEnvelope, globalBuffer, BUFFER_SIZE );
1186 if( cryptStatusError( count ) )
1187 return( FALSE );
1188 if( !destroyEnvelope( cryptEnvelope ) )
1189 return( FALSE );
1190
1191 /* Tell them what happened */
1192 printf( "Enveloped data has size %d bytes.\n", count );
1193 debugDump( dumpFileName, globalBuffer, count );
1194
1195 /* De-envelope the data and make sure that the result matches what we
1196 pushed */
1197 count = envelopeDecrypt( globalBuffer, count, cryptContext );
1198 if( count <= 0 )
1199 return( FALSE );
1200 if( !compareData( ENVELOPE_TESTDATA, ENVELOPE_TESTDATA_SIZE,
1201 globalBuffer, ENVELOPE_TESTDATA_SIZE ) )
1202 return( FALSE );
1203
1204 /* Clean up */
1205 cryptDestroyContext( cryptContext );
1206 puts( "Enveloping of encrypted data succeeded.\n" );
1207 return( TRUE );
1208 }
1209
testEnvelopeCrypt(void)1210 int testEnvelopeCrypt( void )
1211 {
1212 if( !envelopeCrypt( "env_kekn", FALSE, CRYPT_FORMAT_CRYPTLIB ) )
1213 return( FALSE ); /* Indefinite length */
1214 return( envelopeCrypt( "env_kek", TRUE, CRYPT_FORMAT_CRYPTLIB ) );
1215 } /* Datasize */
1216
1217
1218 /* Test password-based encrypted enveloping */
1219
envelopePasswordDecrypt(BYTE * buffer,const int length)1220 static int envelopePasswordDecrypt( BYTE *buffer, const int length )
1221 {
1222 CRYPT_ENVELOPE cryptEnvelope;
1223 int count;
1224
1225 /* Create the envelope, push in the data, pop the de-enveloped result,
1226 and destroy the envelope */
1227 if( !createDeenvelope( &cryptEnvelope ) )
1228 return( FALSE );
1229 count = pushData( cryptEnvelope, buffer, length, TEST_PASSWORD,
1230 paramStrlen( TEST_PASSWORD ) );
1231 if( cryptStatusError( count ) )
1232 return( FALSE );
1233 count = popData( cryptEnvelope, buffer, BUFFER_SIZE );
1234 if( cryptStatusError( count ) )
1235 return( FALSE );
1236 if( !destroyEnvelope( cryptEnvelope ) )
1237 return( FALSE );
1238 return( count );
1239 }
1240
envelopePasswordCrypt(const char * dumpFileName,const BOOLEAN useDatasize,const BOOLEAN useAltCipher,const BOOLEAN multiKeys,const CRYPT_FORMAT_TYPE formatType)1241 static int envelopePasswordCrypt( const char *dumpFileName,
1242 const BOOLEAN useDatasize,
1243 const BOOLEAN useAltCipher,
1244 const BOOLEAN multiKeys,
1245 const CRYPT_FORMAT_TYPE formatType )
1246 {
1247 CRYPT_ENVELOPE cryptEnvelope;
1248 int count;
1249
1250 printf( "Testing %s%spassword-encrypted enveloping%s",
1251 ( formatType == CRYPT_FORMAT_PGP ) ? "PGP " : "",
1252 multiKeys ? "multiple-" : "",
1253 ( useDatasize && ( formatType != CRYPT_FORMAT_PGP ) ) ? \
1254 " with datasize hint" : "" );
1255 if( useAltCipher )
1256 {
1257 printf( ( formatType == CRYPT_FORMAT_PGP ) ? \
1258 " with non-default cipher type" : " and stream cipher" );
1259 }
1260 puts( "..." );
1261
1262 /* Create the envelope, push in a password and the data, pop the
1263 enveloped result, and destroy the envelope */
1264 if( !createEnvelope( &cryptEnvelope, formatType ) )
1265 return( FALSE );
1266 if( useAltCipher )
1267 {
1268 int status;
1269
1270 if( formatType == CRYPT_FORMAT_PGP )
1271 {
1272 status = cryptSetAttribute( cryptEnvelope,
1273 CRYPT_OPTION_ENCR_ALGO,
1274 CRYPT_ALGO_AES );
1275 }
1276 else
1277 {
1278 CRYPT_CONTEXT sessionKeyContext;
1279
1280 /* Test enveloping with an IV-less stream cipher, which tests
1281 the handling of algorithms that can't be used to wrap
1282 themselves in the RecipientInfo */
1283 status = cryptCreateContext( &sessionKeyContext, CRYPT_UNUSED,
1284 CRYPT_ALGO_RC4 );
1285 if( status == CRYPT_ERROR_NOTAVAIL )
1286 {
1287 puts( "Warning: Couldn't set non-default envelope cipher "
1288 "RC4, this may be disabled\n in this build of "
1289 "cryptlib.\n" );
1290 if( !destroyEnvelope( cryptEnvelope ) )
1291 return( FALSE );
1292 return( TRUE );
1293 }
1294 if( cryptStatusOK( status ) )
1295 status = cryptGenerateKey( sessionKeyContext );
1296 if( cryptStatusOK( status ) )
1297 {
1298 status = cryptSetAttribute( cryptEnvelope,
1299 CRYPT_ENVINFO_SESSIONKEY,
1300 sessionKeyContext );
1301 cryptDestroyContext( sessionKeyContext );
1302 }
1303 }
1304 if( cryptStatusError( status ) )
1305 {
1306 printf( "Couldn't set non-default envelope cipher, error code "
1307 "%d, line %d.\n", status, __LINE__ );
1308 return( FALSE );
1309 }
1310 }
1311 if( !addEnvInfoString( cryptEnvelope, CRYPT_ENVINFO_PASSWORD,
1312 TEST_PASSWORD, paramStrlen( TEST_PASSWORD ) ) )
1313 return( FALSE );
1314 if( multiKeys )
1315 {
1316 if( !addEnvInfoString( cryptEnvelope, CRYPT_ENVINFO_PASSWORD,
1317 TEXT( "Password1" ),
1318 paramStrlen( TEXT( "Password1" ) ) ) || \
1319 !addEnvInfoString( cryptEnvelope, CRYPT_ENVINFO_PASSWORD,
1320 TEXT( "Password2" ),
1321 paramStrlen( TEXT( "Password2" ) ) ) || \
1322 !addEnvInfoString( cryptEnvelope, CRYPT_ENVINFO_PASSWORD,
1323 TEXT( "Password3" ),
1324 paramStrlen( TEXT( "Password3" ) ) ) )
1325 return( FALSE );
1326 }
1327 if( useDatasize )
1328 cryptSetAttribute( cryptEnvelope, CRYPT_ENVINFO_DATASIZE,
1329 ENVELOPE_TESTDATA_SIZE );
1330 count = pushData( cryptEnvelope, ENVELOPE_TESTDATA,
1331 ENVELOPE_TESTDATA_SIZE, NULL, 0 );
1332 if( cryptStatusError( count ) )
1333 return( FALSE );
1334 count = popData( cryptEnvelope, globalBuffer, BUFFER_SIZE );
1335 if( cryptStatusError( count ) )
1336 return( FALSE );
1337 if( !destroyEnvelope( cryptEnvelope ) )
1338 return( FALSE );
1339
1340 /* Tell them what happened */
1341 printf( "Enveloped data has size %d bytes.\n", count );
1342 debugDump( dumpFileName, globalBuffer, count );
1343
1344 /* De-envelope the data and make sure that the result matches what we
1345 pushed */
1346 count = envelopePasswordDecrypt( globalBuffer, count );
1347 if( count <= 0 )
1348 return( FALSE );
1349 if( !compareData( ENVELOPE_TESTDATA, ENVELOPE_TESTDATA_SIZE,
1350 globalBuffer, count ) )
1351 return( FALSE );
1352
1353 /* Clean up */
1354 puts( "Enveloping of password-encrypted data succeeded.\n" );
1355 return( TRUE );
1356 }
1357
testEnvelopePasswordCrypt(void)1358 int testEnvelopePasswordCrypt( void )
1359 {
1360 if( !envelopePasswordCrypt( "env_pasn", FALSE, FALSE, FALSE, CRYPT_FORMAT_CRYPTLIB ) )
1361 return( FALSE ); /* Indefinite length */
1362 if( !envelopePasswordCrypt( "env_pas", TRUE, FALSE, FALSE, CRYPT_FORMAT_CRYPTLIB ) )
1363 return( FALSE ); /* Datasize */
1364 if( !envelopePasswordCrypt( "env_mpas", TRUE, FALSE, TRUE, CRYPT_FORMAT_CRYPTLIB ) )
1365 return( FALSE ); /* Datasize, multiple keys */
1366 if( !envelopePasswordCrypt( "env_pas.pgp", TRUE, FALSE, FALSE, CRYPT_FORMAT_PGP ) )
1367 return( FALSE ); /* PGP format */
1368 if( !envelopePasswordCrypt( "env_pasa.pgp", TRUE, TRUE, FALSE, CRYPT_FORMAT_PGP ) )
1369 return( FALSE ); /* PGP format */
1370 return( envelopePasswordCrypt( "env_pasr", TRUE, TRUE, FALSE, CRYPT_FORMAT_CRYPTLIB ) );
1371 } /* IV-less cipher */
1372
1373 /* Test boundary conditions for encrypted enveloping. The strategies are:
1374
1375 All: Push data up to the EOC, then:
1376
1377 Strategy 0: Pop exact data length.
1378 Strategy 1: Pop as much as possible.
1379
1380 For encrypted data, 8 bytes should be left un-popped since the enveloping
1381 code hasn't hit the EOCs yet and so can't know how many bytes at the end
1382 are payload vs. padding */
1383
envelopeBoundaryTest(const BOOLEAN usePassword,const int strategy)1384 static int envelopeBoundaryTest( const BOOLEAN usePassword,
1385 const int strategy )
1386 {
1387 CRYPT_ENVELOPE cryptEnvelope;
1388 BYTE encBuffer[ 1024 ];
1389 int eocPos = 34;
1390 int count, status;
1391
1392 printf( "Testing %senveloping boundary condition handling, "
1393 "strategy %d...\n", usePassword ? "encrypted " : "",
1394 strategy );
1395
1396 /* If we're using password-based enveloping then the EOC position can
1397 vary depending on the hash algorithm used */
1398 if( usePassword )
1399 {
1400 int hashAlgo;
1401
1402 status = cryptGetAttribute( CRYPT_UNUSED, CRYPT_OPTION_KEYING_ALGO,
1403 &hashAlgo );
1404 if( cryptStatusError( status ) )
1405 return( FALSE );
1406 eocPos = ( hashAlgo == CRYPT_ALGO_SHA1 ) ? 182 : 216;
1407 }
1408
1409 /* Create an envelope and envelope some data using indefinite-length
1410 encoding */
1411 if( !createEnvelope( &cryptEnvelope, CRYPT_FORMAT_CRYPTLIB ) )
1412 return( FALSE );
1413 if( usePassword )
1414 {
1415 if( !addEnvInfoString( cryptEnvelope, CRYPT_ENVINFO_PASSWORD,
1416 TEST_PASSWORD, paramStrlen( TEST_PASSWORD ) ) )
1417 return( FALSE );
1418 }
1419 count = pushData( cryptEnvelope, ENVELOPE_TESTDATA,
1420 ENVELOPE_TESTDATA_SIZE, NULL, 0 );
1421 if( cryptStatusError( count ) )
1422 return( FALSE );
1423 count = popData( cryptEnvelope, encBuffer, 1024 );
1424 if( cryptStatusError( count ) )
1425 return( FALSE );
1426 if( !destroyEnvelope( cryptEnvelope ) )
1427 return( FALSE );
1428 if( strategy == 0 ) /* Different strategies produce the same output */
1429 debugDump( usePassword ? "env_ovfe" : "env_ovfd", encBuffer, count );
1430
1431 /* Make sure the EOCs are at the expected position */
1432 if( usePassword )
1433 {
1434 assert( ( encBuffer[ eocPos - 1 ] != 0 || \
1435 encBuffer[ eocPos - 2 ] != 0 || \
1436 encBuffer[ eocPos - 3 ] != 0 ) && \
1437 encBuffer[ eocPos ] == 0 && encBuffer[ eocPos + 1 ] == 0 );
1438 }
1439 else
1440 {
1441 assert( encBuffer[ eocPos - 2 ] == \
1442 ENVELOPE_TESTDATA[ ENVELOPE_TESTDATA_SIZE - 2 ] && \
1443 encBuffer[ eocPos - 1 ] == \
1444 ENVELOPE_TESTDATA[ ENVELOPE_TESTDATA_SIZE - 1 ] && \
1445 encBuffer[ eocPos ] == 0 && encBuffer[ eocPos + 1 ] == 0 );
1446 /* [ -2 ] = last char, [ -1 ] = '\0' */
1447 }
1448
1449 /* De-envelope the data. We can't use envelopePasswordDecrypt() for this
1450 because we need to perform custom data handling to test the boundary
1451 conditions. First we push the data up to the EOC */
1452 if( !createDeenvelope( &cryptEnvelope ) )
1453 return( FALSE );
1454 status = cryptPushData( cryptEnvelope, encBuffer, eocPos, &count );
1455 if( cryptStatusError( status ) )
1456 {
1457 if( !usePassword || status != CRYPT_ENVELOPE_RESOURCE )
1458 {
1459 printExtError( cryptEnvelope, "cryptPushData()", status, __LINE__ );
1460 return( status );
1461 }
1462 if( !addEnvInfoString( cryptEnvelope, CRYPT_ENVINFO_PASSWORD,
1463 TEST_PASSWORD, paramStrlen( TEST_PASSWORD ) ) )
1464 return( FALSE );
1465 }
1466
1467 /* Then we pop data either up to the EOC or as much as we can */
1468 if( strategy == 0 )
1469 {
1470 /* Pop the exact data length */
1471 status = cryptPopData( cryptEnvelope, globalBuffer,
1472 ENVELOPE_TESTDATA_SIZE, &count );
1473 }
1474 else
1475 {
1476 /* Pop as much as we can get */
1477 status = cryptPopData( cryptEnvelope, globalBuffer,
1478 BUFFER_SIZE, &count );
1479 }
1480 if( cryptStatusError( status ) )
1481 {
1482 printf( "Error popping data before final-EOC push, error code %d, "
1483 "line %d.\n", status, __LINE__ );
1484 return( FALSE );
1485 }
1486 if( usePassword )
1487 {
1488 /* If it's password-encrypted, there are five EOCs at the end of the
1489 data */
1490 status = cryptPushData( cryptEnvelope, encBuffer + eocPos, 10,
1491 &count );
1492 }
1493 else
1494 {
1495 /* If it's plain data, there are three EOCs at the end of the data */
1496 status = cryptPushData( cryptEnvelope, encBuffer + eocPos, 6,
1497 &count );
1498 }
1499 if( cryptStatusError( status ) )
1500 {
1501 printf( "Error pushing final EOCs, error code %d, line %d.\n",
1502 status, __LINE__ );
1503 return( FALSE );
1504 }
1505
1506 /* Finally we pop the remaining data. Due to the internal envelope
1507 buffering strategy the remaining data can be either the cipher
1508 blocksize or ENVELOPE_TESTDATA_SIZE - blocksize if we're working with
1509 encrypted data */
1510 status = cryptPopData( cryptEnvelope, &globalBuffer, BUFFER_SIZE,
1511 &count );
1512 if( cryptStatusError( status ) )
1513 {
1514 printf( "Error popping data after final-EOC push, error code %d, "
1515 "line %d.\n", status, __LINE__ );
1516 return( FALSE );
1517 }
1518 if( usePassword )
1519 {
1520 int blockSize;
1521
1522 status = cryptGetAttribute( cryptEnvelope, CRYPT_CTXINFO_BLOCKSIZE,
1523 &blockSize );
1524 if( cryptStatusError( status ) )
1525 return( FALSE );
1526 if( count != ( ENVELOPE_TESTDATA_SIZE % blockSize ) && \
1527 count != ENVELOPE_TESTDATA_SIZE - \
1528 ( ENVELOPE_TESTDATA_SIZE % blockSize ) )
1529 {
1530 printf( "Final data count should have been %d, was %d, "
1531 "line %d.\n", ENVELOPE_TESTDATA_SIZE % blockSize, count,
1532 __LINE__ );
1533 return( FALSE );
1534 }
1535 }
1536 else
1537 {
1538 if( count != 0 )
1539 {
1540 printf( "Final data count should have been 0, was %d, "
1541 "line %d.\n", count, __LINE__ );
1542 return( FALSE );
1543 }
1544 }
1545 if( !destroyEnvelope( cryptEnvelope ) )
1546 return( FALSE );
1547
1548 /* Clean up */
1549 puts( "Enveloping boundary-condition handling succeeded.\n" );
1550 return( TRUE );
1551 }
1552
testEnvelopePasswordCryptBoundary(void)1553 int testEnvelopePasswordCryptBoundary( void )
1554 {
1555 if( !envelopeBoundaryTest( FALSE, 0 ) )
1556 return( FALSE );
1557 if( !envelopeBoundaryTest( FALSE, 1 ) )
1558 return( FALSE );
1559 if( !envelopeBoundaryTest( TRUE, 0 ) )
1560 return( FALSE );
1561 return( envelopeBoundaryTest( TRUE, 1 ) );
1562 }
1563
1564 /* Test PKC-encrypted enveloping */
1565
envelopePKCDecrypt(BYTE * buffer,const int length,const KEYFILE_TYPE keyFileType,const CRYPT_HANDLE externalCryptKeyset)1566 static int envelopePKCDecrypt( BYTE *buffer, const int length,
1567 const KEYFILE_TYPE keyFileType,
1568 const CRYPT_HANDLE externalCryptKeyset )
1569 {
1570 CRYPT_ENVELOPE cryptEnvelope;
1571 int count, status;
1572
1573 assert( ( keyFileType != KEYFILE_NONE && \
1574 externalCryptKeyset == CRYPT_UNUSED ) || \
1575 ( keyFileType == KEYFILE_NONE && \
1576 externalCryptKeyset != CRYPT_UNUSED ) );
1577
1578 /* Create the envelope and push in the decryption keyset */
1579 if( !createDeenvelope( &cryptEnvelope ) )
1580 return( FALSE );
1581 if( keyFileType != KEYFILE_NONE )
1582 {
1583 CRYPT_KEYSET cryptKeyset;
1584 const C_STR keysetName = getKeyfileName( keyFileType, TRUE );
1585
1586 /* Add the decryption keyset */
1587 status = cryptKeysetOpen( &cryptKeyset, CRYPT_UNUSED,
1588 CRYPT_KEYSET_FILE, keysetName,
1589 CRYPT_KEYOPT_READONLY );
1590 if( cryptStatusError( status ) )
1591 return( FALSE );
1592 status = addEnvInfoNumeric( cryptEnvelope,
1593 CRYPT_ENVINFO_KEYSET_DECRYPT,
1594 cryptKeyset );
1595 cryptKeysetClose( cryptKeyset );
1596 }
1597 else
1598 {
1599 /* We're using a device to handle decryption keys */
1600 status = addEnvInfoNumeric( cryptEnvelope,
1601 CRYPT_ENVINFO_KEYSET_DECRYPT,
1602 externalCryptKeyset );
1603 }
1604 if( status <= 0 )
1605 return( FALSE );
1606
1607 /* Push in the data */
1608 if( keyFileType != KEYFILE_NONE )
1609 {
1610 const C_STR password = getKeyfilePassword( keyFileType );
1611
1612 count = pushData( cryptEnvelope, buffer, length, password,
1613 paramStrlen( password ) );
1614 }
1615 else
1616 count = pushData( cryptEnvelope, buffer, length, NULL, 0 );
1617 if( cryptStatusError( count ) )
1618 return( FALSE );
1619 count = popData( cryptEnvelope, buffer, BUFFER_SIZE );
1620 if( cryptStatusError( count ) )
1621 return( FALSE );
1622 if( !destroyEnvelope( cryptEnvelope ) )
1623 return( FALSE );
1624 return( count );
1625 }
1626
envelopePKCDecryptDirect(BYTE * buffer,const int length,const KEYFILE_TYPE keyFileType)1627 static int envelopePKCDecryptDirect( BYTE *buffer, const int length,
1628 const KEYFILE_TYPE keyFileType )
1629 {
1630 CRYPT_ENVELOPE cryptEnvelope;
1631 CRYPT_CONTEXT cryptContext;
1632 int count, status;
1633
1634 /* Create the envelope and get the decryption key */
1635 if( !createDeenvelope( &cryptEnvelope ) )
1636 return( FALSE );
1637 status = getPrivateKey( &cryptContext,
1638 getKeyfileName( keyFileType, TRUE ),
1639 getKeyfileUserID( keyFileType, TRUE ),
1640 getKeyfilePassword( keyFileType ) );
1641 if( cryptStatusError( status ) )
1642 return( FALSE );
1643
1644 /* Push in the data */
1645 count = pushData( cryptEnvelope, buffer, length, NULL, cryptContext );
1646 cryptDestroyContext( cryptContext );
1647 if( cryptStatusError( count ) )
1648 return( FALSE );
1649 count = popData( cryptEnvelope, buffer, BUFFER_SIZE );
1650 if( cryptStatusError( count ) )
1651 return( FALSE );
1652 if( !destroyEnvelope( cryptEnvelope ) )
1653 return( FALSE );
1654 return( count );
1655 }
1656
envelopePKCCrypt(const char * dumpFileName,const BOOLEAN useDatasize,const KEYFILE_TYPE keyFileType,const BOOLEAN useRecipient,const BOOLEAN useMultipleKeyex,const BOOLEAN useAltAlgo,const BOOLEAN useDirectKey,const CRYPT_FORMAT_TYPE formatType,const CRYPT_CONTEXT externalCryptContext,const CRYPT_HANDLE externalCryptKeyset)1657 static int envelopePKCCrypt( const char *dumpFileName,
1658 const BOOLEAN useDatasize,
1659 const KEYFILE_TYPE keyFileType,
1660 const BOOLEAN useRecipient,
1661 const BOOLEAN useMultipleKeyex,
1662 const BOOLEAN useAltAlgo,
1663 const BOOLEAN useDirectKey,
1664 const CRYPT_FORMAT_TYPE formatType,
1665 const CRYPT_CONTEXT externalCryptContext,
1666 const CRYPT_HANDLE externalCryptKeyset )
1667 {
1668 CRYPT_ENVELOPE cryptEnvelope;
1669 CRYPT_KEYSET cryptKeyset;
1670 CRYPT_HANDLE cryptKey;
1671 const C_STR keysetName = TEXT( "<None>" );
1672 const C_STR keyID = TEXT( "<None>" );
1673 int count, status;
1674
1675 assert( ( keyFileType != KEYFILE_NONE && \
1676 externalCryptContext == CRYPT_UNUSED && \
1677 externalCryptKeyset == CRYPT_UNUSED ) || \
1678 ( keyFileType == KEYFILE_NONE && \
1679 externalCryptContext != CRYPT_UNUSED && \
1680 externalCryptKeyset != CRYPT_UNUSED ) );
1681
1682 if( !keyReadOK )
1683 {
1684 puts( "Couldn't find key files, skipping test of public-key "
1685 "encrypted enveloping..." );
1686 return( TRUE );
1687 }
1688 if( keyFileType != KEYFILE_NONE )
1689 {
1690 /* When reading keys we have to explicitly use the first matching
1691 key in the PGP 2.x keyring since the remaining keys are (for some
1692 reason) stored unencrypted, and the keyring read code will
1693 disallow the use of the key if it's stored in this manner */
1694 keysetName = getKeyfileName( keyFileType, FALSE );
1695 keyID = ( keyFileType == KEYFILE_PGP ) ? \
1696 TEXT( "test" ) : getKeyfileUserID( keyFileType, FALSE );
1697 }
1698 fprintf( outputStream, "Testing %spublic-key encrypted enveloping",
1699 ( formatType == CRYPT_FORMAT_PGP ) ? \
1700 ( ( keyFileType == KEYFILE_PGP ) ? "PGP " : "OpenPGP " ) : "" );
1701 if( useDatasize && ( formatType != CRYPT_FORMAT_PGP ) && \
1702 !( useRecipient || useMultipleKeyex || useDirectKey ) )
1703 fprintf( outputStream, " with datasize hint" );
1704 fprintf( outputStream, " using " );
1705 fprintf( outputStream, ( keyFileType == KEYFILE_PGP ) ? \
1706 ( ( formatType == CRYPT_FORMAT_PGP ) ? \
1707 "PGP key" : "raw public key" ) : \
1708 "X.509 cert" );
1709 if( useRecipient && !useAltAlgo )
1710 fprintf( outputStream, " and recipient info" );
1711 if( useMultipleKeyex )
1712 fprintf( outputStream, " and additional keying info" );
1713 if( useAltAlgo )
1714 fprintf( outputStream, " and alt.encr.algo" );
1715 if( useDirectKey )
1716 fprintf( outputStream, " and direct key add" );
1717 fputs( "...\n", outputStream );
1718
1719 /* Open the keyset and either get the public key explicitly (to make sure
1720 that this version works) or leave the keyset open to allow it to be
1721 added to the envelope */
1722 if( keyFileType != KEYFILE_NONE )
1723 {
1724 if( useRecipient )
1725 {
1726 status = cryptKeysetOpen( &cryptKeyset, CRYPT_UNUSED,
1727 CRYPT_KEYSET_FILE, keysetName,
1728 CRYPT_KEYOPT_READONLY );
1729 if( cryptStatusError( status ) )
1730 {
1731 printf( "Couldn't open keyset '%s', status %d, line %d.\n",
1732 keysetName, status, __LINE__ );
1733 return( FALSE );
1734 }
1735 }
1736 else
1737 {
1738 status = getPublicKey( &cryptKey, keysetName, keyID );
1739 if( cryptStatusError( status ) )
1740 return( FALSE );
1741 }
1742 }
1743 else
1744 {
1745 cryptKey = externalCryptContext;
1746 cryptKeyset = externalCryptKeyset;
1747 }
1748
1749 /* Create the envelope, push in the recipient info or public key and data,
1750 pop the enveloped result, and destroy the envelope */
1751 if( !createEnvelope( &cryptEnvelope, formatType ) )
1752 return( FALSE );
1753 if( useAltAlgo )
1754 {
1755 /* Specify the use of an alternative (non-default) bulk encryption
1756 algorithm */
1757 if( !addEnvInfoNumeric( cryptEnvelope, CRYPT_OPTION_ENCR_ALGO,
1758 CRYPT_ALGO_3DES ) )
1759 return( FALSE );
1760 }
1761 if( useRecipient )
1762 {
1763 /* Add recipient information to the envelope. Since we can't
1764 guarantee for enveloping with cryptlib native key types that we
1765 have a real public-key keyset available at this time (it's created
1766 by a different part of the self-test code that may not have run
1767 yet) we're actually reading the public key from the private-key
1768 keyset. Normally we couldn't do this, however since PKCS #15
1769 doesn't store email addresses as key ID's (there's no need to),
1770 the code will drop back to trying for a match on the key label.
1771 Because of this we specify the private key label instead of a real
1772 recipient email address. Note that this trick only works because
1773 of a coincidence of two or three factors and wouldn't normally be
1774 used, it's only used here because we can't assume that a real
1775 public-key keyset is available for use.
1776
1777 An additional test that would be useful is the ability to handle
1778 multiple key exchange records, however the keyset kludge makes
1779 this rather difficult. Since the functionality is tested by the
1780 use of multiple passwords in the conventional-encryption test
1781 earlier on this isn't a major issue */
1782 if( !addEnvInfoNumeric( cryptEnvelope, CRYPT_ENVINFO_KEYSET_ENCRYPT,
1783 cryptKeyset ) || \
1784 !addEnvInfoString( cryptEnvelope, CRYPT_ENVINFO_RECIPIENT,
1785 keyID, paramStrlen( keyID ) ) )
1786 return( FALSE );
1787 cryptKeysetClose( cryptKeyset );
1788 }
1789 else
1790 {
1791 if( !addEnvInfoNumeric( cryptEnvelope, CRYPT_ENVINFO_PUBLICKEY,
1792 cryptKey ) )
1793 return( FALSE );
1794
1795 /* Test the ability to detect the addition of a duplicate key */
1796 if( !( useRecipient || useMultipleKeyex || useDirectKey ) )
1797 {
1798 if( addEnvInfoNumeric( cryptEnvelope, CRYPT_ENVINFO_PUBLICKEY,
1799 cryptKey ) )
1800 {
1801 printf( "Addition of duplicate key succeeded when it "
1802 "should have failed,\nline %d.\n", __LINE__ );
1803 return( FALSE );
1804 }
1805 fputs( " (The above message indicates that the test condition "
1806 "was successfully\n checked).", outputStream );
1807 }
1808
1809 if( keyFileType != KEYFILE_NONE )
1810 cryptDestroyObject( cryptKey );
1811 }
1812 if( useMultipleKeyex && \
1813 !addEnvInfoString( cryptEnvelope, CRYPT_ENVINFO_PASSWORD,
1814 TEXT( "test" ), paramStrlen( TEXT( "test" ) ) ) )
1815 return( FALSE );
1816 if( useDatasize )
1817 cryptSetAttribute( cryptEnvelope, CRYPT_ENVINFO_DATASIZE,
1818 ENVELOPE_TESTDATA_SIZE );
1819 count = pushData( cryptEnvelope, ENVELOPE_TESTDATA,
1820 ENVELOPE_TESTDATA_SIZE, NULL, 0 );
1821 if( cryptStatusError( count ) )
1822 return( FALSE );
1823 count = popData( cryptEnvelope, globalBuffer, BUFFER_SIZE );
1824 if( cryptStatusError( count ) )
1825 return( FALSE );
1826 if( !destroyEnvelope( cryptEnvelope ) )
1827 return( FALSE );
1828
1829 /* Tell them what happened */
1830 fprintf( outputStream, "Enveloped data has size %d bytes.\n", count );
1831 debugDump( dumpFileName, globalBuffer, count );
1832
1833 /* De-envelope the data and make sure that the result matches what we
1834 pushed */
1835 if( useDirectKey )
1836 count = envelopePKCDecryptDirect( globalBuffer, count, keyFileType );
1837 else
1838 {
1839 count = envelopePKCDecrypt( globalBuffer, count, keyFileType,
1840 externalCryptKeyset );
1841 }
1842 if( count <= 0 )
1843 return( FALSE );
1844 if( !compareData( ENVELOPE_TESTDATA, ENVELOPE_TESTDATA_SIZE,
1845 globalBuffer, count ) )
1846 return( FALSE );
1847
1848 /* Clean up */
1849 fputs( "Enveloping of public-key encrypted data succeeded.\n",
1850 outputStream );
1851 return( TRUE );
1852 }
1853
testEnvelopePKCCrypt(void)1854 int testEnvelopePKCCrypt( void )
1855 {
1856 #ifndef USE_PGP2
1857 puts( "Skipping raw public-key and PGP enveloping, which requires PGP "
1858 "2.x support to\n be enabled.\n" );
1859 #else
1860 if( cryptQueryCapability( CRYPT_ALGO_IDEA, NULL ) == CRYPT_ERROR_NOTAVAIL )
1861 {
1862 puts( "Skipping raw public-key and PGP enveloping, which requires "
1863 "the IDEA cipher to\nbe enabled.\n" );
1864 }
1865 else
1866 {
1867 if( !envelopePKCCrypt( "env_pkcn", FALSE, KEYFILE_PGP, FALSE, FALSE, FALSE, FALSE, CRYPT_FORMAT_CRYPTLIB, CRYPT_UNUSED, CRYPT_UNUSED ) )
1868 return( FALSE ); /* Indefinite length, raw key */
1869 if( !envelopePKCCrypt( "env_pkc", TRUE, KEYFILE_PGP, FALSE, FALSE, FALSE, FALSE, CRYPT_FORMAT_CRYPTLIB, CRYPT_UNUSED, CRYPT_UNUSED ) )
1870 return( FALSE ); /* Datasize, raw key */
1871 if( !envelopePKCCrypt( "env_pkc.pgp", TRUE, KEYFILE_PGP, FALSE, FALSE, FALSE, FALSE, CRYPT_FORMAT_PGP, CRYPT_UNUSED, CRYPT_UNUSED ) )
1872 return( FALSE ); /* PGP format */
1873 if( !envelopePKCCrypt( "env_pkc.pgp", TRUE, KEYFILE_PGP, TRUE, FALSE, FALSE, FALSE, CRYPT_FORMAT_PGP, CRYPT_UNUSED, CRYPT_UNUSED ) )
1874 return( FALSE ); /* PGP format, recipient */
1875 if( !envelopePKCCrypt( "env_pkc.pgp", TRUE, KEYFILE_PGP, FALSE, FALSE, FALSE, TRUE, CRYPT_FORMAT_PGP, CRYPT_UNUSED, CRYPT_UNUSED ) )
1876 return( FALSE ); /* PGP format, decrypt key provided directly */
1877 if( !envelopePKCCrypt( "env_pkca.pgp", TRUE, KEYFILE_PGP, TRUE, FALSE, TRUE, FALSE, CRYPT_FORMAT_PGP, CRYPT_UNUSED, CRYPT_UNUSED ) )
1878 return( FALSE ); /* PGP format, recipient, nonstandard bulk encr.algo */
1879 }
1880 #endif /* USE_PGP2 */
1881 if( !envelopePKCCrypt( "env_crt.pgp", TRUE, KEYFILE_X509, TRUE, FALSE, FALSE, FALSE, CRYPT_FORMAT_PGP, CRYPT_UNUSED, CRYPT_UNUSED ) )
1882 return( FALSE ); /* PGP format, certificate */
1883 if( !envelopePKCCrypt( "env_crtn", FALSE, KEYFILE_X509, FALSE, FALSE, FALSE, FALSE, CRYPT_FORMAT_CRYPTLIB, CRYPT_UNUSED, CRYPT_UNUSED ) )
1884 return( FALSE ); /* Indefinite length, certificate */
1885 if( !envelopePKCCrypt( "env_crt", TRUE, KEYFILE_X509, FALSE, FALSE, FALSE, FALSE, CRYPT_FORMAT_CRYPTLIB, CRYPT_UNUSED, CRYPT_UNUSED ) )
1886 return( FALSE ); /* Datasize, certificate */
1887 if( !envelopePKCCrypt( "env_crt", TRUE, KEYFILE_X509, FALSE, FALSE, FALSE, TRUE, CRYPT_FORMAT_CRYPTLIB, CRYPT_UNUSED, CRYPT_UNUSED ) )
1888 return( FALSE ); /* Datasize, certificate, decrypt key provided directly */
1889 if( !envelopePKCCrypt( "env_crt", TRUE, KEYFILE_X509, TRUE, FALSE, FALSE, FALSE, CRYPT_FORMAT_CRYPTLIB, CRYPT_UNUSED, CRYPT_UNUSED ) )
1890 return( FALSE ); /* Datasize, cerficate, recipient */
1891 return( envelopePKCCrypt( "env_crtp", TRUE, KEYFILE_X509, FALSE, TRUE, FALSE, FALSE, CRYPT_FORMAT_CRYPTLIB, CRYPT_UNUSED, CRYPT_UNUSED ) );
1892 } /* Datasize, cerficate+password */
1893
testEnvelopePKCCryptEx(const CRYPT_CONTEXT cryptContext,const CRYPT_HANDLE decryptKeyset)1894 int testEnvelopePKCCryptEx( const CRYPT_CONTEXT cryptContext,
1895 const CRYPT_HANDLE decryptKeyset )
1896 {
1897 /* Note that we can't test PGP enveloping with device-based keys since
1898 the PGP keyIDs aren't supported by any known device type */
1899 #if 0
1900 if( !envelopePKCCrypt( "env_pkc.pgp", TRUE, KEYFILE_NONE, FALSE, FALSE, FALSE, FALSE, CRYPT_FORMAT_PGP, cryptContext, decryptKeyset ) )
1901 return( FALSE ); /* PGP format */
1902 #endif
1903 return( envelopePKCCrypt( "env_pkc", TRUE, KEYFILE_NONE, FALSE, FALSE, FALSE, FALSE, CRYPT_FORMAT_CRYPTLIB, cryptContext, decryptKeyset ) );
1904 } /* Datasize, raw key */
1905
1906 #if defined( _MSC_VER ) && ( _MSC_VER == 1200 ) && !defined( NDEBUG )
1907
1908 /* Perform an iterated envelope/deenvelope test to catch errors that only
1909 occur in a small subset of runs. This is used to check for problems in
1910 data-dependant operations, e.g. leading-zero truncation which only crops
1911 up in 1/256 runs.
1912
1913 Since this is quite time-consuming and a single test applies to all
1914 versions and builds of the code, we only peform it for VC++ 6.0 debug
1915 builds */
1916
1917 #define NO_ITERS 1000
1918
envelopePKCIterated(const CRYPT_FORMAT_TYPE formatType)1919 static int envelopePKCIterated( const CRYPT_FORMAT_TYPE formatType )
1920 {
1921 CRYPT_CONTEXT cryptPubKey, cryptPrivKey;
1922 int i, status;
1923
1924 printf( "Testing %d iterations of %s enveloping to check for "
1925 "pad/trunc.errors...\n", NO_ITERS,
1926 ( formatType == CRYPT_FORMAT_CRYPTLIB ) ? "cryptlib" : "PGP" );
1927 status = getPublicKey( &cryptPubKey,
1928 getKeyfileName( KEYFILE_X509, FALSE ),
1929 getKeyfileUserID( KEYFILE_X509, FALSE ) );
1930 assert( cryptStatusOK( status ) );
1931 status = getPrivateKey( &cryptPrivKey,
1932 getKeyfileName( KEYFILE_X509, FALSE ),
1933 getKeyfileUserID( KEYFILE_X509, FALSE ),
1934 getKeyfilePassword( KEYFILE_X509 ) );
1935 assert( cryptStatusOK( status ) );
1936 outputStream = fopen( "nul:", "w" );
1937 assert( outputStream != NULL );
1938 for( i = 0; i < NO_ITERS; i++ )
1939 {
1940 CRYPT_ENVELOPE cryptEnvelope;
1941 int count, status;
1942
1943 printf( "%d.\r", i );
1944
1945 /* Envelope the data */
1946 status = createEnvelope( &cryptEnvelope, formatType );
1947 assert( status == TRUE );
1948 status = addEnvInfoNumeric( cryptEnvelope, CRYPT_ENVINFO_PUBLICKEY,
1949 cryptPubKey );
1950 assert( status == TRUE );
1951 cryptSetAttribute( cryptEnvelope, CRYPT_ENVINFO_DATASIZE,
1952 ENVELOPE_TESTDATA_SIZE );
1953 count = pushData( cryptEnvelope, ENVELOPE_TESTDATA,
1954 ENVELOPE_TESTDATA_SIZE, NULL, 0 );
1955 assert( !cryptStatusError( count ) );
1956 count = popData( cryptEnvelope, globalBuffer, BUFFER_SIZE );
1957 assert( !cryptStatusError( count ) );
1958 destroyEnvelope( cryptEnvelope );
1959
1960 /* De-envelope the data */
1961 status = createDeenvelope( &cryptEnvelope );
1962 assert( status == TRUE );
1963 status = pushData( cryptEnvelope, globalBuffer, count, NULL,
1964 cryptPrivKey );
1965 if( cryptStatusError( status ) )
1966 {
1967 printf( "\nFailed, iteration = %d.\n", i );
1968 debugDump( "r:/out.der", globalBuffer, count );
1969 destroyEnvelope( cryptEnvelope );
1970 return( FALSE );
1971 }
1972 count = popData( cryptEnvelope, globalBuffer, BUFFER_SIZE );
1973 assert( !cryptStatusError( count ) );
1974 destroyEnvelope( cryptEnvelope );
1975 }
1976 outputStream = stdout;
1977 cryptDestroyContext( cryptPubKey );
1978 cryptDestroyContext( cryptPrivKey );
1979
1980 printf( "Tested %d iterations of %s PKC enveloping.\n", NO_ITERS,
1981 ( formatType == CRYPT_FORMAT_CRYPTLIB ) ? "cryptlib" : "PGP" );
1982 return( TRUE );
1983 }
1984
testEnvelopePKCIterated(void)1985 int testEnvelopePKCIterated( void )
1986 {
1987 if( !envelopePKCIterated( CRYPT_FORMAT_CRYPTLIB ) )
1988 return( FALSE );
1989 return( envelopePKCIterated( CRYPT_FORMAT_PGP ) );
1990 }
1991 #else
testEnvelopePKCIterated(void)1992 int testEnvelopePKCIterated( void )
1993 {
1994 return( TRUE );
1995 }
1996 #endif /* VC++ 6.0 */
1997
1998 /* Test each encryption algorithm */
1999
envelopeAlgoCrypt(const char * dumpFileName,const CRYPT_ALGO_TYPE cryptAlgo)2000 static int envelopeAlgoCrypt( const char *dumpFileName,
2001 const CRYPT_ALGO_TYPE cryptAlgo )
2002 {
2003 CRYPT_ENVELOPE cryptEnvelope;
2004 CRYPT_HANDLE encryptKey, decryptKey;
2005 const char *algoName = \
2006 ( cryptAlgo == CRYPT_ALGO_RSA ) ? "RSA" : \
2007 ( cryptAlgo == CRYPT_ALGO_ELGAMAL ) ? "Elgamal" : "<Unknown>";
2008 int count;
2009
2010 printf( "Testing %s public-key encrypted enveloping...\n", algoName );
2011
2012 /* Create the en/decryption contexts */
2013 switch( cryptAlgo )
2014 {
2015 case CRYPT_ALGO_RSA:
2016 if( !loadRSAContexts( CRYPT_UNUSED, &encryptKey, &decryptKey ) )
2017 return( FALSE );
2018 break;
2019
2020 case CRYPT_ALGO_ELGAMAL:
2021 if( !loadElgamalContexts( &encryptKey, &decryptKey ) )
2022 return( FALSE );
2023 break;
2024
2025 default:
2026 printf( "Unknown encryption algorithm %d, line %d.\n",
2027 cryptAlgo, __LINE__ );
2028 return( FALSE );
2029 }
2030
2031 /* Create the envelope, push in the public key and data, pop the
2032 enveloped result, and destroy the envelope */
2033 if( !createEnvelope( &cryptEnvelope, CRYPT_FORMAT_CRYPTLIB ) )
2034 return( FALSE );
2035 if( !addEnvInfoNumeric( cryptEnvelope, CRYPT_ENVINFO_PUBLICKEY,
2036 encryptKey ) )
2037 return( FALSE );
2038 cryptDestroyContext( encryptKey );
2039 cryptSetAttribute( cryptEnvelope, CRYPT_ENVINFO_DATASIZE,
2040 ENVELOPE_TESTDATA_SIZE );
2041 count = pushData( cryptEnvelope, ENVELOPE_TESTDATA,
2042 ENVELOPE_TESTDATA_SIZE, NULL, 0 );
2043 if( cryptStatusError( count ) )
2044 return( FALSE );
2045 count = popData( cryptEnvelope, globalBuffer, BUFFER_SIZE );
2046 if( cryptStatusError( count ) )
2047 return( FALSE );
2048 if( !destroyEnvelope( cryptEnvelope ) )
2049 return( FALSE );
2050
2051 /* Tell them what happened */
2052 printf( "%s-enveloped data has size %d bytes.\n", algoName, count );
2053 debugDump( dumpFileName, globalBuffer, count );
2054
2055 /* De-envelope the data and make sure that the result matches what we
2056 pushed */
2057 if( !createDeenvelope( &cryptEnvelope ) )
2058 return( FALSE );
2059 count = pushData( cryptEnvelope, globalBuffer, count, NULL,
2060 decryptKey );
2061 cryptDestroyContext( decryptKey );
2062 if( cryptStatusError( count ) )
2063 return( FALSE );
2064 count = popData( cryptEnvelope, globalBuffer, BUFFER_SIZE );
2065 if( cryptStatusError( count ) )
2066 return( FALSE );
2067 if( !destroyEnvelope( cryptEnvelope ) )
2068 return( FALSE );
2069 if( !compareData( ENVELOPE_TESTDATA, ENVELOPE_TESTDATA_SIZE,
2070 globalBuffer, count ) )
2071 return( FALSE );
2072
2073 /* Clean up */
2074 puts( "Enveloping of public-key encrypted data succeeded.\n" );
2075 return( TRUE );
2076 }
2077
testEnvelopePKCCryptAlgo(void)2078 int testEnvelopePKCCryptAlgo( void )
2079 {
2080 if( !envelopeAlgoCrypt( "env_pkc_rsa", CRYPT_ALGO_RSA ) )
2081 return( FALSE );
2082 if( cryptStatusOK( cryptQueryCapability( CRYPT_ALGO_ELGAMAL, NULL ) ) && \
2083 !envelopeAlgoCrypt( "env_pkc_elg", CRYPT_ALGO_ELGAMAL ) )
2084 return( FALSE );
2085 return( TRUE );
2086 }
2087
2088 /* Test PKC-encrypted enveloping with multiple recipients */
2089
envelopePKCCryptMulti(const char * dumpFileName,const BOOLEAN useKeyFile,const int recipientNo,const CRYPT_FORMAT_TYPE formatType)2090 static int envelopePKCCryptMulti( const char *dumpFileName,
2091 const BOOLEAN useKeyFile,
2092 const int recipientNo,
2093 const CRYPT_FORMAT_TYPE formatType )
2094 {
2095 CRYPT_ENVELOPE cryptEnvelope;
2096 CRYPT_HANDLE cryptKey1, cryptKey2;
2097 int count, status;
2098
2099 if( !keyReadOK )
2100 {
2101 puts( "Couldn't find key files, skipping test of public-key "
2102 "encrypted enveloping..." );
2103 return( TRUE );
2104 }
2105 printf( "Testing %spublic-key encrypted enveloping with multiple recipients,\n",
2106 ( formatType == CRYPT_FORMAT_PGP ) ? "PGP " : "" );
2107 printf( " recipient %d to decrypt", recipientNo );
2108 puts( "..." );
2109
2110 /* Open the keysets and get the two public keys */
2111 status = getPublicKey( &cryptKey1,
2112 getKeyfileName( KEYFILE_X509, FALSE ),
2113 getKeyfileUserID( KEYFILE_X509, FALSE ) );
2114 if( cryptStatusOK( status ) )
2115 {
2116 status = getPublicKey( &cryptKey2,
2117 getKeyfileName( KEYFILE_X509_ALT, FALSE ),
2118 getKeyfileUserID( KEYFILE_X509_ALT, FALSE ) );
2119 }
2120 if( cryptStatusError( status ) )
2121 return( FALSE );
2122
2123 /* Create the envelope, push in the keys and data, pop the enveloped
2124 result, and destroy the envelope */
2125 if( !createEnvelope( &cryptEnvelope, formatType ) )
2126 return( FALSE );
2127 if( !addEnvInfoNumeric( cryptEnvelope, CRYPT_ENVINFO_PUBLICKEY,
2128 cryptKey1 ) )
2129 return( FALSE );
2130 if( !addEnvInfoNumeric( cryptEnvelope, CRYPT_ENVINFO_PUBLICKEY,
2131 cryptKey2 ) )
2132 return( FALSE );
2133 cryptDestroyObject( cryptKey1 );
2134 cryptDestroyObject( cryptKey2 );
2135 cryptSetAttribute( cryptEnvelope, CRYPT_ENVINFO_DATASIZE,
2136 ENVELOPE_TESTDATA_SIZE );
2137 count = pushData( cryptEnvelope, ENVELOPE_TESTDATA,
2138 ENVELOPE_TESTDATA_SIZE, NULL, 0 );
2139 if( cryptStatusError( count ) )
2140 return( FALSE );
2141 count = popData( cryptEnvelope, globalBuffer, BUFFER_SIZE );
2142 if( cryptStatusError( count ) )
2143 return( FALSE );
2144 if( !destroyEnvelope( cryptEnvelope ) )
2145 return( FALSE );
2146
2147 /* Tell them what happened */
2148 printf( "Enveloped data has size %d bytes.\n", count );
2149 debugDump( dumpFileName, globalBuffer, count );
2150
2151 /* De-envelope the data and make sure that the result matches what we
2152 pushed */
2153 count = envelopePKCDecryptDirect( globalBuffer, count,
2154 ( recipientNo == 1 ) ? KEYFILE_X509 : \
2155 KEYFILE_X509_ALT );
2156 if( count <= 0 )
2157 return( FALSE );
2158 if( !compareData( ENVELOPE_TESTDATA, ENVELOPE_TESTDATA_SIZE,
2159 globalBuffer, count ) )
2160 return( FALSE );
2161
2162 /* Clean up */
2163 puts( "Enveloping of public-key encrypted data with multiple recipients succeeded.\n" );
2164 return( TRUE );
2165 }
2166
testEnvelopePKCCryptMulti(void)2167 int testEnvelopePKCCryptMulti( void )
2168 {
2169 if( cryptQueryCapability( CRYPT_ALGO_IDEA, NULL ) == CRYPT_ERROR_NOTAVAIL )
2170 {
2171 puts( "Skipping raw public-key and PGP enveloping, which requires "
2172 "the IDEA cipher to\nbe enabled.\n" );
2173 }
2174 else
2175 {
2176 if( !envelopePKCCryptMulti( "env_pkc_mp", FALSE, 1, CRYPT_FORMAT_PGP ) )
2177 return( FALSE ); /* PGP format, multiple recip, key #1 decrypts */
2178 if( !envelopePKCCryptMulti( "env_pkc_mp", FALSE, 2, CRYPT_FORMAT_PGP ) )
2179 return( FALSE ); /* PGP format, multiple recip, key #2 decrypts */
2180 }
2181 if( !envelopePKCCryptMulti( "env_pkc_m", FALSE, 1, CRYPT_FORMAT_CRYPTLIB ) )
2182 return( FALSE ); /* Multiple recipients, key #1 decrypts */
2183 return( envelopePKCCryptMulti( "env_pkc_m", FALSE, 2, CRYPT_FORMAT_CRYPTLIB ) );
2184 } /* Multiple recipients, key #2 decrypts */
2185
2186 /****************************************************************************
2187 * *
2188 * Signed Enveloping Routines *
2189 * *
2190 ****************************************************************************/
2191
2192 /* Test signed enveloping */
2193
getSigCheckResult(const CRYPT_ENVELOPE cryptEnvelope,const CRYPT_CONTEXT sigCheckContext,const BOOLEAN showAttributes,const BOOLEAN isAuthData)2194 static int getSigCheckResult( const CRYPT_ENVELOPE cryptEnvelope,
2195 const CRYPT_CONTEXT sigCheckContext,
2196 const BOOLEAN showAttributes,
2197 const BOOLEAN isAuthData )
2198 {
2199 int value, status;
2200
2201 /* Display all of the attributes that we've got */
2202 if( showAttributes && !displayAttributes( cryptEnvelope ) )
2203 return( FALSE );
2204
2205 /* Determine the result of the signature check. If it's authenticated
2206 data there's no need to do anything with keys, if it's signed data
2207 we have to do some extra processing */
2208 if( !isAuthData )
2209 {
2210 status = cryptGetAttribute( cryptEnvelope, CRYPT_ATTRIBUTE_CURRENT,
2211 &value );
2212 if( cryptStatusError( status ) )
2213 {
2214 printf( "Read of required attribute for signature check "
2215 "returned status %d, line %d.\n", status, __LINE__ );
2216 return( FALSE );
2217 }
2218 if( value != CRYPT_ENVINFO_SIGNATURE )
2219 {
2220 printf( "Envelope requires unexpected enveloping information "
2221 "type %d, line %d.\n", value, __LINE__ );
2222 return( FALSE );
2223 }
2224 if( sigCheckContext != CRYPT_UNUSED )
2225 {
2226 status = cryptSetAttribute( cryptEnvelope, CRYPT_ENVINFO_SIGNATURE,
2227 sigCheckContext );
2228 if( cryptStatusError( status ) )
2229 {
2230 printf( "Attempt to add signature check key returned status "
2231 "%d, line %d.\n", status, __LINE__ );
2232 return( FALSE );
2233 }
2234 }
2235 }
2236 status = cryptGetAttribute( cryptEnvelope, CRYPT_ENVINFO_SIGNATURE_RESULT,
2237 &value );
2238 if( cryptStatusError( status ) )
2239 {
2240 printf( "Signature check returned status %d, line %d.\n", status,
2241 __LINE__ );
2242 return( FALSE );
2243 }
2244 switch( value )
2245 {
2246 case CRYPT_OK:
2247 puts( "Signature is valid." );
2248 return( TRUE );
2249
2250 case CRYPT_ERROR_NOTFOUND:
2251 puts( "Cannot find key to check signature." );
2252 break;
2253
2254 case CRYPT_ERROR_SIGNATURE:
2255 puts( "Signature is invalid." );
2256 break;
2257
2258 case CRYPT_ERROR_NOTAVAIL:
2259 puts( "Warning: Couldn't verify signature due to use of a "
2260 "deprecated/insecure\n signature algorithm.\n" );
2261 return( TRUE );
2262
2263 default:
2264 printf( "Signature check failed, result = %d, line %d.\n",
2265 value, __LINE__ );
2266 }
2267
2268 return( FALSE );
2269 }
2270
envelopeSigCheck(BYTE * buffer,const int length,const CRYPT_CONTEXT hashContext,const CRYPT_CONTEXT sigContext,const KEYFILE_TYPE keyFileType,const BOOLEAN detachedSig,const CRYPT_FORMAT_TYPE formatType)2271 static int envelopeSigCheck( BYTE *buffer, const int length,
2272 const CRYPT_CONTEXT hashContext,
2273 const CRYPT_CONTEXT sigContext,
2274 const KEYFILE_TYPE keyFileType,
2275 const BOOLEAN detachedSig,
2276 const CRYPT_FORMAT_TYPE formatType )
2277 {
2278 CRYPT_ENVELOPE cryptEnvelope;
2279 int count, status;
2280
2281 /* Create the envelope and push in the sig.check keyset if we're not
2282 using a supplied context for the sig.check */
2283 if( !createDeenvelope( &cryptEnvelope ) )
2284 return( FALSE );
2285 if( sigContext == CRYPT_UNUSED )
2286 {
2287 const C_STR keysetName = getKeyfileName( keyFileType, FALSE );
2288 CRYPT_KEYSET cryptKeyset;
2289
2290 status = cryptKeysetOpen( &cryptKeyset, CRYPT_UNUSED,
2291 CRYPT_KEYSET_FILE, keysetName,
2292 CRYPT_KEYOPT_READONLY );
2293 if( cryptStatusOK( status ) )
2294 status = addEnvInfoNumeric( cryptEnvelope,
2295 CRYPT_ENVINFO_KEYSET_SIGCHECK, cryptKeyset );
2296 cryptKeysetClose( cryptKeyset );
2297 if( status <= 0 )
2298 return( FALSE );
2299 }
2300
2301 /* If the hash value is being supplied externally, add it to the envelope
2302 before we add the signature data */
2303 if( detachedSig && hashContext != CRYPT_UNUSED )
2304 {
2305 status = cryptSetAttribute( cryptEnvelope,
2306 CRYPT_ENVINFO_DETACHEDSIGNATURE, TRUE );
2307 if( cryptStatusOK( status ) )
2308 status = cryptSetAttribute( cryptEnvelope, CRYPT_ENVINFO_HASH,
2309 hashContext );
2310 if( cryptStatusError( status ) )
2311 {
2312 printf( "Couldn't add externally-generated hash value to "
2313 "envelope, status %d, line %d.\n", status, __LINE__ );
2314 return( FALSE );
2315 }
2316 }
2317
2318 /* Push in the data */
2319 count = pushData( cryptEnvelope, buffer, length, NULL, 0 );
2320 if( !cryptStatusError( count ) )
2321 {
2322 if( detachedSig )
2323 {
2324 if( hashContext == CRYPT_UNUSED )
2325 count = pushData( cryptEnvelope, ENVELOPE_TESTDATA,
2326 ENVELOPE_TESTDATA_SIZE, NULL, 0 );
2327 }
2328 else
2329 count = popData( cryptEnvelope, buffer, length );
2330 }
2331 if( cryptStatusError( count ) )
2332 return( FALSE );
2333
2334 /* Determine the result of the signature check */
2335 if( !getSigCheckResult( cryptEnvelope, sigContext, TRUE, FALSE ) )
2336 return( FALSE );
2337
2338 /* If we're testing the automatic upgrade of the envelope hash function
2339 to a stronger one, make sure that the hash algorithm was upgraded */
2340 if( keyFileType == KEYFILE_X509_ALT )
2341 {
2342 /* There's no easy way to retrieve the hash algorithm used for
2343 signing from the envelope since it's a low-level internal
2344 attribute, so the only way to verify that the algorithm upgrade
2345 was successful is by running dumpasn1 on the output data file */
2346 }
2347
2348 /* If we supplied the sig-checking key, make sure that it's handled
2349 correctly by the envelope. We shouldn't be able to read it back from
2350 a PGP envelope, and from a cryptlib/CMS/SMIME envelope we should get
2351 back only a certificate, not the full private key that we added */
2352 if( sigContext != CRYPT_UNUSED )
2353 {
2354 CRYPT_CONTEXT sigCheckContext;
2355
2356 status = cryptGetAttribute( cryptEnvelope, CRYPT_ENVINFO_SIGNATURE,
2357 &sigCheckContext );
2358 if( formatType == CRYPT_FORMAT_PGP )
2359 {
2360 /* If it's a PGP envelope, we can't retrieve the signing key from
2361 it */
2362 if( cryptStatusOK( status ) )
2363 {
2364 printf( "Attempt to read signature check key from PGP "
2365 "envelope succeeded when it\nshould have failed, "
2366 "line %d.\n", __LINE__ );
2367 return( FALSE );
2368 }
2369 }
2370 else
2371 {
2372 CRYPT_ENVELOPE testEnvelope;
2373
2374 /* If it's a cryptlib/CMS/SMIME envelope then we should be able
2375 to retrieve the signing key from it */
2376 if( cryptStatusError( status ) )
2377 {
2378 printf( "Couldn't retrieve signature check key from "
2379 "envelope, status %d, line %d.\n", status,
2380 __LINE__ );
2381 return( FALSE );
2382 }
2383
2384 /* The signing key should be a pure certificate, not the private
2385 key+certificate combination that we pushed in. Note that the
2386 following will result in an error message being printed in
2387 addEnvInfoNumeric() */
2388 if( !createEnvelope( &testEnvelope, CRYPT_FORMAT_CRYPTLIB ) )
2389 return( FALSE );
2390 if( addEnvInfoNumeric( testEnvelope, CRYPT_ENVINFO_SIGNATURE,
2391 sigCheckContext ) )
2392 {
2393 printf( "Retrieved signature check key is a private key, not "
2394 "a certificate, line %d.\n", __LINE__ );
2395 return( FALSE );
2396 }
2397 else
2398 {
2399 puts( " (The above message indicates that the test "
2400 "condition was successfully\n checked)." );
2401 }
2402 if( !destroyEnvelope( testEnvelope ) )
2403 return( FALSE );
2404 cryptDestroyCert( sigCheckContext );
2405 }
2406 }
2407
2408 /* Clean up */
2409 if( !destroyEnvelope( cryptEnvelope ) )
2410 return( FALSE );
2411 return( count );
2412 }
2413
envelopeSign(const void * data,const int dataLength,const char * dumpFileName,const KEYFILE_TYPE keyFileType,const BOOLEAN useDatasize,const BOOLEAN useCustomHash,const BOOLEAN useSuppliedKey,const CRYPT_CONTENT_TYPE contentType,const CRYPT_FORMAT_TYPE formatType)2414 static int envelopeSign( const void *data, const int dataLength,
2415 const char *dumpFileName,
2416 const KEYFILE_TYPE keyFileType,
2417 const BOOLEAN useDatasize,
2418 const BOOLEAN useCustomHash,
2419 const BOOLEAN useSuppliedKey,
2420 const CRYPT_CONTENT_TYPE contentType,
2421 const CRYPT_FORMAT_TYPE formatType )
2422 {
2423 CRYPT_ENVELOPE cryptEnvelope;
2424 CRYPT_KEYSET cryptKeyset;
2425 CRYPT_CONTEXT cryptContext DUMMY_INIT;
2426 char filenameBuffer[ FILENAME_BUFFER_SIZE ];
2427 int count, status;
2428
2429 if( !keyReadOK )
2430 {
2431 puts( "Couldn't find key files, skipping test of signed "
2432 "enveloping..." );
2433 return( TRUE );
2434 }
2435 printf( "Testing %ssigned enveloping%s",
2436 ( formatType == CRYPT_FORMAT_PGP ) ? "PGP " : \
2437 ( formatType == CRYPT_FORMAT_SMIME ) ? "S/MIME " : "",
2438 ( useDatasize && formatType != CRYPT_FORMAT_PGP && \
2439 keyFileType != KEYFILE_X509_ALT ) ? \
2440 " with datasize hint" : "" );
2441 if( useCustomHash )
2442 {
2443 printf( " %s custom hash",
2444 ( formatType == CRYPT_FORMAT_PGP ) ? "with" :"and" );
2445 }
2446 if( contentType == CRYPT_CONTENT_NONE )
2447 {
2448 printf( " using %s",
2449 ( keyFileType == KEYFILE_OPENPGP_HASH ) ? "raw DSA key" : \
2450 ( keyFileType == KEYFILE_PGP ) ? "raw public key" : \
2451 useSuppliedKey ? "supplied X.509 cert" : "X.509 cert" );
2452 }
2453 if( keyFileType == KEYFILE_X509_ALT )
2454 printf( " and automatic hash upgrade" );
2455 if( contentType != CRYPT_CONTENT_NONE )
2456 printf( " and custom content type" );
2457 puts( "..." );
2458
2459 /* Get the private key */
2460 if( keyFileType == KEYFILE_OPENPGP_HASH || keyFileType == KEYFILE_PGP )
2461 {
2462 const C_STR keysetName = getKeyfileName( keyFileType, TRUE );
2463
2464 status = cryptKeysetOpen( &cryptKeyset, CRYPT_UNUSED,
2465 CRYPT_KEYSET_FILE, keysetName,
2466 CRYPT_KEYOPT_READONLY );
2467 if( cryptStatusOK( status ) )
2468 {
2469 status = cryptGetPrivateKey( cryptKeyset, &cryptContext,
2470 CRYPT_KEYID_NAME,
2471 getKeyfileUserID( KEYFILE_PGP, TRUE ),
2472 getKeyfilePassword( KEYFILE_PGP ) );
2473 cryptKeysetClose( cryptKeyset );
2474 }
2475 }
2476 else
2477 {
2478 filenameFromTemplate( filenameBuffer, USER_PRIVKEY_FILE_TEMPLATE, 2 );
2479 status = getPrivateKey( &cryptContext,
2480 ( keyFileType == KEYFILE_X509 ) ? \
2481 USER_PRIVKEY_FILE : filenameBuffer,
2482 USER_PRIVKEY_LABEL, TEST_PRIVKEY_PASSWORD );
2483 }
2484 if( cryptStatusError( status ) )
2485 {
2486 printf( "Read of private key from key file failed, status %d, "
2487 "line %d, cannot test enveloping.\n", status, __LINE__ );
2488 return( FALSE );
2489 }
2490
2491 /* Create the envelope, push in the signing key, any extra information,
2492 and the data to sign, pop the enveloped result, and destroy the
2493 envelope */
2494 if( !createEnvelope( &cryptEnvelope, formatType ) )
2495 return( FALSE );
2496 if( contentType != CRYPT_CONTENT_NONE )
2497 {
2498 if( !addEnvInfoNumeric( cryptEnvelope, CRYPT_ENVINFO_CONTENTTYPE,
2499 contentType ) )
2500 return( FALSE );
2501 }
2502 if( !addEnvInfoNumeric( cryptEnvelope, CRYPT_ENVINFO_SIGNATURE,
2503 cryptContext ) )
2504 {
2505 cryptDestroyContext( cryptContext );
2506 cryptDestroyEnvelope( cryptEnvelope );
2507 if( formatType == CRYPT_FORMAT_PGP && \
2508 contentType != CRYPT_CONTENT_NONE )
2509 {
2510 puts( " (This is an expected result since this test verifies "
2511 "rejection of an\n attempt to set a non-data content "
2512 "type with PGP)." );
2513 return( TRUE );
2514 }
2515 return( FALSE );
2516 }
2517 else
2518 {
2519 if( formatType == CRYPT_FORMAT_PGP && \
2520 contentType != CRYPT_CONTENT_NONE )
2521 {
2522 printf( "Addition of custom content type to PGP envelope "
2523 "succeeded when it should\nhave failed, line %d.\n",
2524 __LINE__ );
2525 return( FALSE );
2526 }
2527 }
2528 if( cryptSetAttribute( cryptEnvelope, CRYPT_ENVINFO_SIGNATURE,
2529 cryptContext ) != CRYPT_ERROR_INITED )
2530 {
2531 puts( "Addition of duplicate key to envelope wasn't detected." );
2532 return( FALSE );
2533 }
2534 if( !useSuppliedKey )
2535 cryptDestroyContext( cryptContext );
2536 if( useDatasize )
2537 cryptSetAttribute( cryptEnvelope, CRYPT_ENVINFO_DATASIZE,
2538 dataLength );
2539 count = pushData( cryptEnvelope, data, dataLength, NULL, 0 );
2540 if( cryptStatusError( count ) )
2541 return( FALSE );
2542 count = popData( cryptEnvelope, globalBuffer, BUFFER_SIZE );
2543 if( cryptStatusError( count ) )
2544 return( FALSE );
2545 if( !destroyEnvelope( cryptEnvelope ) )
2546 return( FALSE );
2547
2548 /* Tell them what happened */
2549 printf( "Enveloped data has size %d bytes.\n", count );
2550 debugDump( dumpFileName, globalBuffer, count );
2551
2552 /* De-envelope the data and make sure that the result matches what we
2553 pushed */
2554 count = envelopeSigCheck( globalBuffer, count, CRYPT_UNUSED,
2555 ( useSuppliedKey ) ? cryptContext : CRYPT_UNUSED,
2556 keyFileType, FALSE, formatType );
2557 if( count <= 0 )
2558 return( FALSE );
2559 if( !compareData( data, dataLength, globalBuffer, count ) )
2560 return( FALSE );
2561 if( useSuppliedKey )
2562 {
2563 /* If the following fails, there's a problem with handling reference
2564 counting for keys */
2565 status = cryptDestroyContext( cryptContext );
2566 if( cryptStatusError( status ) )
2567 {
2568 printf( "Attempt to destroy externally-added sig.check key "
2569 "returned %d, line %d.\n", status, __LINE__ );
2570 return( FALSE );
2571 }
2572 }
2573
2574 /* Clean up */
2575 puts( "Enveloping of signed data succeeded.\n" );
2576 return( TRUE );
2577 }
2578
testEnvelopeSign(void)2579 int testEnvelopeSign( void )
2580 {
2581 #ifndef USE_PGP2
2582 puts( "Skipping raw public-key and PGP signing, which requires PGP 2.x "
2583 "support to\n be enabled.\n" );
2584 #else
2585 if( cryptQueryCapability( CRYPT_ALGO_IDEA, NULL ) == CRYPT_ERROR_NOTAVAIL )
2586 {
2587 puts( "Skipping raw public-key based signing, which requires the "
2588 "IDEA cipher to\nbe enabled.\n" );
2589 }
2590 else
2591 {
2592 if( !envelopeSign( ENVELOPE_TESTDATA, ENVELOPE_TESTDATA_SIZE, "env_sign", KEYFILE_PGP, FALSE, FALSE, FALSE, CRYPT_CONTENT_NONE, CRYPT_FORMAT_CRYPTLIB ) )
2593 return( FALSE ); /* Indefinite length, raw key */
2594 if( !envelopeSign( ENVELOPE_TESTDATA, ENVELOPE_TESTDATA_SIZE, "env_sig", KEYFILE_PGP, TRUE, FALSE, FALSE, CRYPT_CONTENT_NONE, CRYPT_FORMAT_CRYPTLIB ) )
2595 return( FALSE ); /* Datasize, raw key */
2596 if( !envelopeSign( ENVELOPE_TESTDATA, ENVELOPE_TESTDATA_SIZE, "env_sigc", KEYFILE_PGP, TRUE, FALSE, FALSE, CRYPT_CONTENT_COMPRESSEDDATA, CRYPT_FORMAT_CRYPTLIB ) )
2597 return( FALSE ); /* Datasize, raw key, custom content type */
2598 if( !envelopeSign( ENVELOPE_TESTDATA, ENVELOPE_TESTDATA_SIZE, "env_sig.pgp", KEYFILE_PGP, TRUE, FALSE, FALSE, CRYPT_CONTENT_NONE, CRYPT_FORMAT_PGP ) )
2599 return( FALSE ); /* PGP format, datasize, raw key */
2600 if( !envelopeSign( ENVELOPE_TESTDATA, ENVELOPE_TESTDATA_SIZE, "env_sigc.pgp", KEYFILE_PGP, TRUE, FALSE, FALSE, CRYPT_CONTENT_COMPRESSEDDATA, CRYPT_FORMAT_PGP ) )
2601 return( FALSE ); /* PGP format, datasize, raw key, custom content type */
2602 if( !envelopeSign( ENVELOPE_TESTDATA, ENVELOPE_TESTDATA_SIZE, "env_sigd.pgp", KEYFILE_OPENPGP_HASH, TRUE, FALSE, FALSE, CRYPT_CONTENT_NONE, CRYPT_FORMAT_PGP ) )
2603 return( FALSE ); /* PGP format, datasize, raw DSA key */
2604 }
2605 #endif /* USE_PGP2 */
2606 if( !envelopeSign( ENVELOPE_TESTDATA, ENVELOPE_TESTDATA_SIZE, "env_csgn", KEYFILE_X509, FALSE, FALSE, FALSE, CRYPT_CONTENT_NONE, CRYPT_FORMAT_CRYPTLIB ) )
2607 return( FALSE ); /* Indefinite length, certificate */
2608 if( !envelopeSign( ENVELOPE_TESTDATA, ENVELOPE_TESTDATA_SIZE, "env_csg", KEYFILE_X509, TRUE, FALSE, FALSE, CRYPT_CONTENT_NONE, CRYPT_FORMAT_CRYPTLIB ) )
2609 return( FALSE ); /* Datasize, certificate */
2610 if( !envelopeSign( ENVELOPE_TESTDATA, ENVELOPE_TESTDATA_SIZE, "env_csgs", KEYFILE_X509, TRUE, FALSE, FALSE, CRYPT_CONTENT_NONE, CRYPT_FORMAT_SMIME ) )
2611 return( FALSE ); /* Datasize, certificate, S/MIME semantics */
2612 if( !envelopeSign( ENVELOPE_TESTDATA, ENVELOPE_TESTDATA_SIZE, "env_csg", KEYFILE_X509, TRUE, FALSE, TRUE, CRYPT_CONTENT_NONE, CRYPT_FORMAT_CRYPTLIB ) )
2613 return( FALSE ); /* Datasize, certificate, sigcheck key supplied */
2614 if( !envelopeSign( ENVELOPE_TESTDATA, ENVELOPE_TESTDATA_SIZE, "env_csg.pgp", KEYFILE_X509, TRUE, FALSE, FALSE, CRYPT_CONTENT_NONE, CRYPT_FORMAT_PGP ) )
2615 return( FALSE ); /* PGP format, certificate */
2616 #if 0 /* 8/7/2012 Removed since it conflicts with the functionality for
2617 setting hash values for detached signatures. This
2618 capability was never documented in the manual so it's
2619 unlikely that it was ever used */
2620 if( !envelopeSign( ENVELOPE_TESTDATA, ENVELOPE_TESTDATA_SIZE, "env_hsg", KEYFILE_X509, TRUE, TRUE, FALSE, CRYPT_CONTENT_NONE, CRYPT_FORMAT_CRYPTLIB ) )
2621 return( FALSE ); /* Datasize, certificate, externally-suppl.hash */
2622 #endif /* 0 */
2623 return( envelopeSign( ENVELOPE_TESTDATA, ENVELOPE_TESTDATA_SIZE, "env_csg", KEYFILE_X509, TRUE, FALSE, TRUE, CRYPT_CONTENT_NONE, CRYPT_FORMAT_CRYPTLIB ) );
2624 } /* Externally-supplied key, to test isolation of sig.check key */
2625
envelopeAlgoSign(const char * dumpFileName,const CRYPT_ALGO_TYPE cryptAlgo)2626 static int envelopeAlgoSign( const char *dumpFileName,
2627 const CRYPT_ALGO_TYPE cryptAlgo )
2628 {
2629 CRYPT_ENVELOPE cryptEnvelope;
2630 CRYPT_CONTEXT sigKey, sigCheckKey;
2631 const char *algoName = \
2632 ( cryptAlgo == CRYPT_ALGO_RSA ) ? "RSA" : \
2633 ( cryptAlgo == CRYPT_ALGO_DSA ) ? "DSA" : \
2634 ( cryptAlgo == CRYPT_ALGO_ECDSA ) ? "ECDSA" : "<Unknown>";
2635 int count;
2636
2637 printf( "Testing %s signed enveloping...\n", algoName );
2638
2639 /* Create the en/decryption contexts */
2640 switch( cryptAlgo )
2641 {
2642 case CRYPT_ALGO_RSA:
2643 if( !loadRSAContexts( CRYPT_UNUSED, &sigCheckKey, &sigKey ) )
2644 return( FALSE );
2645 break;
2646
2647 case CRYPT_ALGO_DSA:
2648 if( !loadDSAContexts( CRYPT_UNUSED, &sigCheckKey, &sigKey ) )
2649 return( FALSE );
2650 break;
2651
2652 case CRYPT_ALGO_ECDSA:
2653 if( !loadECDSAContexts( CRYPT_UNUSED, &sigCheckKey, &sigKey ) )
2654 return( FALSE );
2655 break;
2656
2657 default:
2658 printf( "Unknown signature algorithm %d, line %d.\n",
2659 cryptAlgo, __LINE__ );
2660 return( FALSE );
2661 }
2662
2663 /* Create the envelope, push in the signing key and the data to sign,
2664 pop the enveloped result, and destroy the envelope */
2665 if( !createEnvelope( &cryptEnvelope, CRYPT_FORMAT_CRYPTLIB ) )
2666 return( FALSE );
2667 if( !addEnvInfoNumeric( cryptEnvelope, CRYPT_ENVINFO_SIGNATURE,
2668 sigKey ) )
2669 return( FALSE );
2670 cryptDestroyContext( sigKey );
2671 cryptSetAttribute( cryptEnvelope, CRYPT_ENVINFO_DATASIZE,
2672 ENVELOPE_TESTDATA_SIZE );
2673 count = pushData( cryptEnvelope, ENVELOPE_TESTDATA,
2674 ENVELOPE_TESTDATA_SIZE, NULL, 0 );
2675 if( cryptStatusError( count ) )
2676 return( FALSE );
2677 count = popData( cryptEnvelope, globalBuffer, BUFFER_SIZE );
2678 if( cryptStatusError( count ) )
2679 return( FALSE );
2680 if( !destroyEnvelope( cryptEnvelope ) )
2681 return( FALSE );
2682
2683 /* Tell them what happened */
2684 printf( "%s-signed data has size %d bytes.\n", algoName, count );
2685 debugDump( dumpFileName, globalBuffer, count );
2686
2687 /* De-envelope the data and make sure that the result matches what we
2688 pushed */
2689 if( !createDeenvelope( &cryptEnvelope ) )
2690 return( FALSE );
2691 count = pushData( cryptEnvelope, globalBuffer, count, NULL, 0 );
2692 if( !cryptStatusError( count ) )
2693 count = popData( cryptEnvelope, globalBuffer, BUFFER_SIZE );
2694 if( cryptStatusError( count ) )
2695 return( FALSE );
2696 if( !getSigCheckResult( cryptEnvelope, sigCheckKey, TRUE, FALSE ) )
2697 return( FALSE );
2698 cryptDestroyContext( sigCheckKey );
2699 if( !destroyEnvelope( cryptEnvelope ) )
2700 return( FALSE );
2701 if( !compareData( ENVELOPE_TESTDATA, ENVELOPE_TESTDATA_SIZE,
2702 globalBuffer, count ) )
2703 return( FALSE );
2704
2705 /* Clean up */
2706 puts( "Enveloping of signed data succeeded.\n" );
2707 return( TRUE );
2708 }
2709
testEnvelopeSignAlgos(void)2710 int testEnvelopeSignAlgos( void )
2711 {
2712 if( !envelopeAlgoSign( "env_sig_rsa", CRYPT_ALGO_RSA ) )
2713 return( FALSE );
2714 if( !envelopeAlgoSign( "env_sig_dsa", CRYPT_ALGO_DSA ) )
2715 return( FALSE );
2716 if( cryptStatusOK( cryptQueryCapability( CRYPT_ALGO_ECDSA, NULL ) ) && \
2717 !envelopeAlgoSign( "env_sig_ecc", CRYPT_ALGO_ECDSA ) )
2718 return( FALSE );
2719 return( TRUE );
2720 }
2721
2722 /* Test envelope signing with automatic upgrade of the signing algorithm to
2723 SHA256 */
2724
testEnvelopeSignHashUpgrade(void)2725 int testEnvelopeSignHashUpgrade( void )
2726 {
2727 return( envelopeSign( ENVELOPE_TESTDATA, ENVELOPE_TESTDATA_SIZE, "env_csgh", KEYFILE_X509_ALT, TRUE, FALSE, FALSE, CRYPT_CONTENT_NONE, CRYPT_FORMAT_CRYPTLIB ) );
2728 }
2729
2730 /* Test signed envelope with forced envelope buffer overflow */
2731
envelopeSignOverflow(const void * data,const int dataLength,const char * dumpFileName,const CRYPT_FORMAT_TYPE formatType,const char * description)2732 static int envelopeSignOverflow( const void *data, const int dataLength,
2733 const char *dumpFileName,
2734 const CRYPT_FORMAT_TYPE formatType,
2735 const char *description )
2736 {
2737 CRYPT_ENVELOPE cryptEnvelope;
2738 CRYPT_CONTEXT cryptContext;
2739 BYTE localBuffer[ 8192 + 4096 ];
2740 const BOOLEAN forceOverflow = ( dataLength <= 8192 ) ? TRUE : FALSE;
2741 int localBufPos, bytesIn, bytesOut, status;
2742
2743 if( !keyReadOK )
2744 {
2745 puts( "Couldn't find key files, skipping test of signed "
2746 "enveloping..." );
2747 return( TRUE );
2748 }
2749 printf( "Testing %ssigned enveloping with forced overflow in %s...\n",
2750 ( formatType == CRYPT_FORMAT_PGP ) ? "PGP " : \
2751 ( formatType == CRYPT_FORMAT_SMIME ) ? "S/MIME " : "",
2752 description );
2753
2754 /* Get the private key */
2755 status = getPrivateKey( &cryptContext, USER_PRIVKEY_FILE,
2756 USER_PRIVKEY_LABEL, TEST_PRIVKEY_PASSWORD );
2757 if( cryptStatusError( status ) )
2758 {
2759 printf( "Read of private key from key file failed, cannot test "
2760 "enveloping, line %d.\n", __LINE__ );
2761 return( FALSE );
2762 }
2763
2764 /* Create the envelope and push in the signing key and any extra
2765 information */
2766 if( !createEnvelope( &cryptEnvelope, formatType ) )
2767 return( FALSE );
2768 if( !addEnvInfoNumeric( cryptEnvelope, CRYPT_ENVINFO_SIGNATURE,
2769 cryptContext ) )
2770 return( FALSE );
2771 cryptDestroyContext( cryptContext );
2772 status = cryptSetAttribute( cryptEnvelope, CRYPT_ENVINFO_DATASIZE,
2773 dataLength );
2774 if( cryptStatusOK( status ) && forceOverflow )
2775 {
2776 /* Set an artificially-small buffer to force an overflow */
2777 status = cryptSetAttribute( cryptEnvelope, CRYPT_ATTRIBUTE_BUFFERSIZE,
2778 8192 );
2779 }
2780 if( cryptStatusError( status ) )
2781 {
2782 printf( "Couldn't set envelope parameters to force overflow, line "
2783 "%d.\n", __LINE__ );
2784 return( FALSE );
2785 }
2786
2787 /* Push in the data to sign. Since we're forcing an overflow, we can't
2788 do this via the usual pushData() but have to do it manually to handle
2789 the restart once the overflow occurs */
2790 status = cryptPushData( cryptEnvelope, data, dataLength, &bytesIn );
2791 if( cryptStatusError( status ) || bytesIn != dataLength )
2792 {
2793 printf( "cryptPushData() failed with status %d, copied %d of %d "
2794 "bytes, line %d.\n", status, bytesIn, dataLength, __LINE__ );
2795 return( FALSE );
2796 }
2797 status = cryptFlushData( cryptEnvelope );
2798 if( forceOverflow && status != CRYPT_ERROR_OVERFLOW )
2799 {
2800 printf( "cryptFlushData() returned status %d, should have been "
2801 "CRYPT_ERROR_OVERFLOW,\n line %d.\n", status, __LINE__ );
2802 return( FALSE );
2803 }
2804 status = cryptPopData( cryptEnvelope, localBuffer, 8192 + 4096,
2805 &bytesOut );
2806 if( cryptStatusError( status ) )
2807 {
2808 printf( "cryptPopData() #1 failed with status %d, line %d.\n",
2809 status, __LINE__ );
2810 return( FALSE );
2811 }
2812 localBufPos = bytesOut;
2813 status = cryptFlushData( cryptEnvelope );
2814 if( cryptStatusError( status ) )
2815 {
2816 printf( "cryptFlushData() failed with error code %d, line %d.\n",
2817 status, __LINE__ );
2818 printErrorAttributeInfo( cryptEnvelope );
2819 return( FALSE );
2820 }
2821 status = cryptPopData( cryptEnvelope, localBuffer + localBufPos,
2822 8192 + 4096 - localBufPos, &bytesOut );
2823 if( cryptStatusError( status ) )
2824 {
2825 printf( "cryptPopData() #2 failed with status %d, line %d.\n",
2826 status, __LINE__ );
2827 return( FALSE );
2828 }
2829 localBufPos += bytesOut;
2830 if( !destroyEnvelope( cryptEnvelope ) )
2831 return( FALSE );
2832
2833 /* Tell them what happened */
2834 printf( "Enveloped data has size %d bytes.\n", localBufPos );
2835 debugDump( dumpFileName, localBuffer, localBufPos );
2836
2837 /* De-envelope the data and make sure that the result matches what we
2838 pushed */
2839 bytesOut = envelopeSigCheck( localBuffer, localBufPos, CRYPT_UNUSED,
2840 CRYPT_UNUSED, KEYFILE_X509, FALSE,
2841 formatType );
2842 if( bytesOut <= 0 )
2843 return( FALSE );
2844 if( !compareData( localBuffer, bytesOut, data, dataLength ) )
2845 return( FALSE );
2846
2847 /* Clean up */
2848 puts( "Enveloping of signed data succeeded.\n" );
2849 return( TRUE );
2850 }
2851
testEnvelopeSignOverflow(void)2852 int testEnvelopeSignOverflow( void )
2853 {
2854 BYTE buffer[ 8192 + 1024 ];
2855
2856 /* Push in just the right amount of data to force an overflow when we
2857 generate the signature, to check overflow handling in the enveloping
2858 code.
2859
2860 For PGP it's almost impossible to invoke overflow handling since the
2861 enveloping code is set up to either emit the signature directly into
2862 the buffer or, via an over-conservative estimation of buffer space,
2863 ensure that the user leaves enough space in the buffer for the entire
2864 sig. For an estimated space requirement of 256 bytes, 8192 - 280
2865 will force the sig into the auxBuffer, but since this is an over-
2866 conservative estimate it'll then be flushed straight into the
2867 envelope buffer. The only way to actually force overflow handling
2868 would be to use the longest possible key size and a certificate with
2869 a large issuerAndSerialNumber.
2870
2871 (In addition to the envelope buffer-overflow check, we also try
2872 enveloping data with a length at the boundary where PGP switches from
2873 2-byte to 4-byte lengths, 8384 bytes, to verify that this works OK).
2874
2875 For CMS, we can cause an overflow in one of two locations. The first,
2876 with 8192 - 1152 bytes of data, causes an overflow when emitting the
2877 signing certs. This is fairly straightforward, the enveloping code
2878 always requires enough room for the signing certs, so all that happens
2879 is that the user pops some data and tries again.
2880
2881 The second overflow is with 8192 - 1280 bytes of data, which causes an
2882 overflow on signing */
2883 memset( buffer, '*', 8192 + 1024 );
2884 if( !envelopeSignOverflow( buffer, 8192 - 280, "env_sigo.pgp", CRYPT_FORMAT_PGP, "signature" ) )
2885 return( FALSE ); /* PGP format, raw key */
2886 if( !envelopeSignOverflow( buffer, 8384 - 6, "env_sigo2.pgp", CRYPT_FORMAT_PGP, "seg.boundary" ) )
2887 return( FALSE ); /* PGP format, raw key */
2888 if( !envelopeSignOverflow( buffer, 8192 - 1152, "env_csgo1", CRYPT_FORMAT_SMIME, "signing certs" ) )
2889 return( FALSE ); /* Datasize, certificate, S/MIME semantics */
2890 return( envelopeSignOverflow( buffer, 8192 - 1280, "env_csgo2", CRYPT_FORMAT_SMIME, "signature" ) );
2891 } /* Datasize, certificate, S/MIME semantics */
2892
2893 /* Test the ability to process indefinite-length data with a break at every
2894 byte position in the file */
2895
testEnvelopeSignIndef(void)2896 int testEnvelopeSignIndef( void )
2897 {
2898 int count, bufPos, status;
2899
2900 puts( "Testing ability to process indefinite-length data at any byte "
2901 "position..." );
2902
2903 /* Read the data to be checked */
2904 count = readFileData( SMIME_SIG_FILE_INDEF,
2905 "Indefinite-length signed data", globalBuffer,
2906 BUFFER_SIZE, 128, FALSE );
2907 if( count <= 0 )
2908 return( FALSE );
2909
2910 /* De-envelope the data, breaking the data quantity at every byte
2911 position */
2912 for( bufPos = 1; bufPos < count; bufPos++ )
2913 {
2914 CRYPT_ENVELOPE cryptEnvelope;
2915 int byteCount;
2916
2917 if( !createDeenvelope( &cryptEnvelope ) )
2918 return( FALSE );
2919 printf( "Testing byte position %d.\r", bufPos );
2920
2921 /* Push the first half of the data */
2922 status = cryptPushData( cryptEnvelope, globalBuffer, bufPos,
2923 &byteCount );
2924 if( cryptStatusError( status ) )
2925 {
2926 /* If we get an underflow error within the header or trailer
2927 then everything's OK and we can continue */
2928 if( status == CRYPT_ERROR_UNDERFLOW && \
2929 ( bufPos < 50 || bufPos > 69 ) )
2930 {
2931 /* We're in the middle of the header or trailer, a
2932 CRYPT_ERROR_UNDERFLOW is expected if we break at this
2933 point */
2934 }
2935 else
2936 return( FALSE );
2937 }
2938 if( byteCount != bufPos )
2939 return( FALSE );
2940
2941 /* Push the second half of the data */
2942 status = cryptPushData( cryptEnvelope, globalBuffer + bufPos,
2943 count - bufPos, &byteCount );
2944 if( cryptStatusOK( status ) )
2945 status = cryptFlushData( cryptEnvelope );
2946 if( cryptStatusError( status ) )
2947 return( FALSE );
2948 if( byteCount != count - bufPos )
2949 return( FALSE );
2950
2951 /* Destroy the envelope. Since we haven't processed the signed data
2952 we'll get a CRYPT_ERROR_INCOMPLETE, so we ignore any error
2953 result */
2954 ( void ) cryptDestroyEnvelope( cryptEnvelope );
2955 }
2956
2957 puts( "Ability to process indefinite-length data at any byte position "
2958 "succeeded.\n" );
2959 return( TRUE );
2960 }
2961
2962 /* Test authenticated (MACd/authEnc) enveloping */
2963
envelopeAuthent(const void * data,const int dataLength,const CRYPT_FORMAT_TYPE formatType,const BOOLEAN useAuthEnc,const BOOLEAN useDatasize,const BOOLEAN usePKC,const int corruptDataLocation)2964 static int envelopeAuthent( const void *data, const int dataLength,
2965 const CRYPT_FORMAT_TYPE formatType,
2966 const BOOLEAN useAuthEnc,
2967 const BOOLEAN useDatasize,
2968 const BOOLEAN usePKC,
2969 const int corruptDataLocation )
2970 {
2971 CRYPT_ENVELOPE cryptEnvelope;
2972 BOOLEAN corruptionDetected = FALSE;
2973 int count, integrityLevel, status;
2974
2975 printf( "Testing %sauthenticated%s enveloping",
2976 ( formatType == CRYPT_FORMAT_PGP ) ? "PGP-format " : "",
2977 useAuthEnc ? "+encrypted" : "" );
2978 if( corruptDataLocation )
2979 printf( " with deliberate corruption of data" );
2980 else
2981 {
2982 if( useDatasize )
2983 printf( " with datasize hint" );
2984 }
2985 puts( "..." );
2986
2987 /* Create the envelope and push in the password after telling the
2988 enveloping code that we want to MAC rather than encrypt */
2989 if( !createEnvelope( &cryptEnvelope, formatType ) )
2990 return( FALSE );
2991 if( !addEnvInfoNumeric( cryptEnvelope, CRYPT_ENVINFO_INTEGRITY,
2992 useAuthEnc ? CRYPT_INTEGRITY_FULL : \
2993 CRYPT_INTEGRITY_MACONLY ) )
2994 {
2995 cryptDestroyEnvelope( cryptEnvelope );
2996 if( formatType == CRYPT_FORMAT_PGP && !useAuthEnc )
2997 {
2998 puts( " (This is an expected result since this test verifies "
2999 "rejection of an\n attempt to use a MAC with PGP).\n" );
3000 return( TRUE );
3001 }
3002 return( FALSE );
3003 }
3004 if( usePKC )
3005 {
3006 CRYPT_CONTEXT cryptKey;
3007
3008 status = getPublicKey( &cryptKey, USER_PRIVKEY_FILE,
3009 USER_PRIVKEY_LABEL );
3010 if( cryptStatusError( status ) )
3011 return( FALSE );
3012 if( !addEnvInfoNumeric( cryptEnvelope, CRYPT_ENVINFO_PUBLICKEY,
3013 cryptKey ) )
3014 {
3015 cryptDestroyContext( cryptKey );
3016 cryptDestroyEnvelope( cryptEnvelope );
3017 if( formatType == CRYPT_FORMAT_CRYPTLIB && !useAuthEnc )
3018 {
3019 puts( " (This is an expected result since this test "
3020 "verifies rejection of an\n attempt to use a PKC "
3021 "with a MAC-only envelope).\n" );
3022 return( TRUE );
3023 }
3024 return( FALSE );
3025 }
3026 cryptDestroyContext( cryptKey );
3027 }
3028 else
3029 {
3030 if( !addEnvInfoString( cryptEnvelope, CRYPT_ENVINFO_PASSWORD,
3031 TEST_PASSWORD, paramStrlen( TEST_PASSWORD ) ) )
3032 return( FALSE );
3033 }
3034 if( formatType == CRYPT_FORMAT_PGP && !useAuthEnc )
3035 {
3036 printf( "Invalid attempt to use MAC-only authentication for "
3037 "PGP-enveloped data wasn't\ndetected, line %d.\n",
3038 __LINE__ );
3039 return( FALSE );
3040 }
3041
3042 /* Push in the data, pop the enveloped result, and destroy the
3043 envelope */
3044 if( useDatasize )
3045 {
3046 cryptSetAttribute( cryptEnvelope, CRYPT_ENVINFO_DATASIZE,
3047 dataLength );
3048 }
3049 count = pushData( cryptEnvelope, data, dataLength, NULL, 0 );
3050 if( cryptStatusError( count ) )
3051 return( FALSE );
3052 count = popData( cryptEnvelope, globalBuffer, BUFFER_SIZE );
3053 if( cryptStatusError( count ) )
3054 return( FALSE );
3055 if( !destroyEnvelope( cryptEnvelope ) )
3056 return( FALSE );
3057
3058 /* Tell them what happened */
3059 printf( "Enveloped data has size %d bytes.\n", count );
3060 debugDump( ( formatType == CRYPT_FORMAT_PGP ) ? "env_mdc.pgp" : \
3061 useAuthEnc ? ( usePKC ? "env_authenp" : "env_authenc" ) : \
3062 useDatasize ? "env_mac" : usePKC ? "env_macp" : "env_macn",
3063 globalBuffer, count );
3064
3065 /* If we're testing sig.verification, corrupt one of the payload bytes.
3066 This is a bit tricky because we have to hardcode the location of the
3067 payload byte, if we change the format at (for example by using a
3068 different algorithm somewhere) then this location will change */
3069 if( corruptDataLocation > 0 )
3070 globalBuffer[ corruptDataLocation ]++;
3071
3072 /* Create the envelope */
3073 if( !createDeenvelope( &cryptEnvelope ) )
3074 return( FALSE );
3075 if( usePKC )
3076 {
3077 CRYPT_KEYSET cryptKeyset;
3078
3079 status = cryptKeysetOpen( &cryptKeyset, CRYPT_UNUSED,
3080 CRYPT_KEYSET_FILE, USER_PRIVKEY_FILE,
3081 CRYPT_KEYOPT_READONLY );
3082 if( cryptStatusError( status ) )
3083 return( FALSE );
3084 if( !addEnvInfoNumeric( cryptEnvelope, CRYPT_ENVINFO_KEYSET_DECRYPT,
3085 cryptKeyset ) )
3086 return( FALSE );
3087 cryptKeysetClose( cryptKeyset );
3088 }
3089
3090 /* Push in the data */
3091 if( usePKC )
3092 {
3093 count = pushData( cryptEnvelope, globalBuffer, count,
3094 TEST_PRIVKEY_PASSWORD,
3095 paramStrlen( TEST_PRIVKEY_PASSWORD ) );
3096 }
3097 else
3098 {
3099 count = pushData( cryptEnvelope, globalBuffer, count,
3100 TEST_PASSWORD, paramStrlen( TEST_PASSWORD ) );
3101 }
3102 if( cryptStatusError( count ) )
3103 {
3104 if( corruptDataLocation && count == CRYPT_ERROR_SIGNATURE )
3105 {
3106 puts( " (This is an expected result since this test verifies "
3107 "handling of\n corrupted authenticated data)." );
3108 corruptionDetected = TRUE;
3109 }
3110 else
3111 return( FALSE );
3112 }
3113 else
3114 {
3115 count = popData( cryptEnvelope, globalBuffer, BUFFER_SIZE );
3116 if( cryptStatusError( count ) )
3117 return( FALSE );
3118 }
3119
3120 /* Make sure that the envelope is reported as being authenticated */
3121 if( cryptStatusError( \
3122 cryptGetAttribute( cryptEnvelope, CRYPT_ENVINFO_INTEGRITY,
3123 &integrityLevel ) ) || \
3124 integrityLevel <= CRYPT_INTEGRITY_NONE )
3125 {
3126 printf( "Integrity-protected envelope is reported as having no "
3127 "integrity protection,\n line %d.\n", __LINE__ );
3128 return( FALSE );
3129 }
3130
3131 /* Determine the result of the MAC check */
3132 if( !getSigCheckResult( cryptEnvelope, CRYPT_UNUSED, FALSE, TRUE ) && \
3133 corruptDataLocation == 0 )
3134 return( FALSE );
3135 if( !destroyEnvelope( cryptEnvelope ) )
3136 return( FALSE );
3137
3138 /* Make sure that we got what we were expecting */
3139 if( corruptDataLocation == 0 )
3140 {
3141 if( !compareData( data, dataLength, globalBuffer, count ) )
3142 return( FALSE );
3143 }
3144 else
3145 {
3146 if( !corruptionDetected )
3147 {
3148 puts( "Corruption of encrypted data wasn't detected." );
3149 return( FALSE );
3150 }
3151 }
3152
3153 /* Clean up */
3154 puts( "Enveloping of authenticated data succeeded.\n" );
3155 return( TRUE );
3156 }
3157
testEnvelopeAuthenticate(void)3158 int testEnvelopeAuthenticate( void )
3159 {
3160 int macAlgo, status;
3161
3162 /* Find out what the default MAC algorithm is. This is required because
3163 the data location that we corrupt changes based on the MAC algorithm
3164 used */
3165 status = cryptGetAttribute( CRYPT_UNUSED, CRYPT_OPTION_ENCR_MAC, &macAlgo );
3166 if( cryptStatusError( status ) )
3167 return( FALSE );
3168
3169 /* MAC-only envelopes are currently only supported via password (or at
3170 least shared-key) key management, using a PKC implies encrypt+MAC.
3171 It's also somewhat unclear what the benefits of using a PKC for a MAC
3172 are, so until there's a demand for this we only allow use with
3173 passwords */
3174 if( !envelopeAuthent( ENVELOPE_TESTDATA, ENVELOPE_TESTDATA_SIZE, CRYPT_FORMAT_CRYPTLIB, FALSE, FALSE, FALSE, 0 ) )
3175 return( FALSE ); /* Indefinite length */
3176 if( !envelopeAuthent( ENVELOPE_TESTDATA, ENVELOPE_TESTDATA_SIZE, CRYPT_FORMAT_CRYPTLIB, FALSE, TRUE, FALSE, 0 ) )
3177 return( FALSE ); /* Datasize */
3178 if( !envelopeAuthent( ENVELOPE_TESTDATA, ENVELOPE_TESTDATA_SIZE, CRYPT_FORMAT_CRYPTLIB, FALSE, TRUE, TRUE, 0 ) )
3179 return( FALSE ); /* Datasize, PKC to check rejection of this format */
3180 if( !envelopeAuthent( ENVELOPE_TESTDATA, ENVELOPE_TESTDATA_SIZE, CRYPT_FORMAT_PGP, FALSE, TRUE, FALSE, 0 ) )
3181 return( FALSE ); /* PGP format to check rejection of this format */
3182 return( envelopeAuthent( ENVELOPE_TESTDATA, ENVELOPE_TESTDATA_SIZE, CRYPT_FORMAT_CRYPTLIB, FALSE, TRUE, FALSE, ( macAlgo == CRYPT_ALGO_HMAC_SHA1 ) ? 175 : 208 ) );
3183 } /* Datasize, corrupt data to check sig.verification */
3184
testEnvelopeAuthEnc(void)3185 int testEnvelopeAuthEnc( void )
3186 {
3187 int macAlgo, status;
3188
3189 /* Find out what the default MAC algorithm is. This is required because
3190 the data location that we corrupt changes based on the MAC algorithm
3191 used */
3192 status = cryptGetAttribute( CRYPT_UNUSED, CRYPT_OPTION_ENCR_MAC, &macAlgo );
3193 if( cryptStatusError( status ) )
3194 return( FALSE );
3195
3196 if( !envelopeAuthent( ENVELOPE_TESTDATA, ENVELOPE_TESTDATA_SIZE, CRYPT_FORMAT_CRYPTLIB, TRUE, FALSE, FALSE, 0 ) )
3197 return( FALSE ); /* Indefinite length */
3198 if( !envelopeAuthent( ENVELOPE_TESTDATA, ENVELOPE_TESTDATA_SIZE, CRYPT_FORMAT_CRYPTLIB, TRUE, TRUE, FALSE, 0 ) )
3199 return( FALSE ); /* Datasize */
3200 if( !envelopeAuthent( ENVELOPE_TESTDATA, ENVELOPE_TESTDATA_SIZE, CRYPT_FORMAT_CRYPTLIB, TRUE, TRUE, TRUE, 0 ) )
3201 return( FALSE ); /* Datasize, PKC */
3202 if( !envelopeAuthent( ENVELOPE_TESTDATA, ENVELOPE_TESTDATA_SIZE, CRYPT_FORMAT_PGP, TRUE, TRUE, FALSE, 0 ) )
3203 return( FALSE ); /* PGP format */
3204 if( !envelopeAuthent( ENVELOPE_TESTDATA, ENVELOPE_TESTDATA_SIZE, CRYPT_FORMAT_PGP, TRUE, TRUE, TRUE, 0 ) )
3205 return( FALSE ); /* PGP format, PKC */
3206 if( !envelopeAuthent( ENVELOPE_TESTDATA, ENVELOPE_TESTDATA_SIZE, CRYPT_FORMAT_CRYPTLIB, TRUE, TRUE, FALSE, ( macAlgo == CRYPT_ALGO_HMAC_SHA1 ) ? 192 : 260 ) )
3207 return( FALSE ); /* Datasize, corrupt payload data to check sig.verification */
3208 return( envelopeAuthent( ENVELOPE_TESTDATA, ENVELOPE_TESTDATA_SIZE, CRYPT_FORMAT_CRYPTLIB, TRUE, TRUE, FALSE, ( macAlgo == CRYPT_ALGO_HMAC_SHA1 ) ? 170 : 228 ) );
3209 } /* Datasize, corrupt metadata to check sig.verification */
3210
3211 /****************************************************************************
3212 * *
3213 * CMS Enveloping Test Routines *
3214 * *
3215 ****************************************************************************/
3216
3217 /* Test CMS signature generation/checking */
3218
displaySigResult(const CRYPT_ENVELOPE cryptEnvelope,const CRYPT_CONTEXT sigCheckContext,const BOOLEAN mustHaveAttributes,const BOOLEAN firstSig)3219 static int displaySigResult( const CRYPT_ENVELOPE cryptEnvelope,
3220 const CRYPT_CONTEXT sigCheckContext,
3221 const BOOLEAN mustHaveAttributes,
3222 const BOOLEAN firstSig )
3223 {
3224 CRYPT_CERTIFICATE signerInfo;
3225 BOOLEAN sigStatus;
3226 int status;
3227
3228 /* Determine the result of the signature check. We only display the
3229 attributes for the first sig since this operation walks the attribute
3230 list,which moves the attribute cursor */
3231 sigStatus = getSigCheckResult( cryptEnvelope, sigCheckContext,
3232 firstSig, FALSE );
3233 if( sigCheckContext != CRYPT_UNUSED && !mustHaveAttributes )
3234 {
3235 /* If this is a PGP signature (indicated by the fact that the
3236 sig-check key isn't included in the signed data and we're not
3237 checking attributes), there's no signer info or extra data
3238 present */
3239 return( sigStatus );
3240 }
3241
3242 /* Report on the signer and signature info. We continue even if the sig.
3243 status is bad since we can still try and display signing info even if
3244 the check fails */
3245 status = cryptGetAttribute( cryptEnvelope, CRYPT_ENVINFO_SIGNATURE,
3246 &signerInfo );
3247 if( cryptStatusError( status ) && sigStatus )
3248 {
3249 printf( "Couldn't retrieve signer information from CMS signature, "
3250 "status = %d, line %d.\n", status, __LINE__ );
3251 return( FALSE );
3252 }
3253 if( cryptStatusOK( status ) )
3254 {
3255 puts( "Signer information is:" );
3256 if( !printCertInfo( signerInfo ) )
3257 return( FALSE );
3258 cryptDestroyCert( signerInfo );
3259 }
3260 status = cryptGetAttribute( cryptEnvelope,
3261 CRYPT_ENVINFO_SIGNATURE_EXTRADATA, &signerInfo );
3262 if( cryptStatusError( status ) && sigStatus && \
3263 ( mustHaveAttributes || status != CRYPT_ERROR_NOTFOUND ) )
3264 {
3265 printf( "Couldn't retrieve signature information from CMS signature, "
3266 "status = %d, line %d.\n", status, __LINE__ );
3267 return( FALSE );
3268 }
3269 if( cryptStatusOK( status ) )
3270 {
3271 puts( "Signature information is:" );
3272 if( !printCertInfo( signerInfo ) )
3273 return( FALSE );
3274 cryptDestroyCert( signerInfo );
3275 }
3276
3277 return( sigStatus );
3278 }
3279
cmsEnvelopeSigCheck(const void * signedData,const int signedDataLength,const CRYPT_CONTEXT sigCheckContext,const CRYPT_CONTEXT hashContext,const BOOLEAN detachedSig,const BOOLEAN hasTimestamp,const BOOLEAN checkData,const BOOLEAN mustHaveAttributes,const BOOLEAN checkWrongKey,const BOOLEAN testRefCount)3280 static int cmsEnvelopeSigCheck( const void *signedData,
3281 const int signedDataLength,
3282 const CRYPT_CONTEXT sigCheckContext,
3283 const CRYPT_CONTEXT hashContext, const BOOLEAN detachedSig,
3284 const BOOLEAN hasTimestamp, const BOOLEAN checkData,
3285 const BOOLEAN mustHaveAttributes, const BOOLEAN checkWrongKey,
3286 const BOOLEAN testRefCount )
3287
3288 {
3289 CRYPT_ENVELOPE cryptEnvelope;
3290 int count, status;
3291
3292 /* Create the (de-)envelope and push in the data. Since this is a CMS
3293 signature that carries its certs with it, there's no need to push in
3294 a sig.check keyset. If it has a detached sig, we need to push two
3295 lots of data, first the signature to set the envelope state, then the
3296 data, however if the hash is being supplied externally we just set the
3297 hash attribute. In addition if it's a detached sig, there's nothing
3298 to be unwrapped so we don't pop any data */
3299 if( !createDeenvelope( &cryptEnvelope ) )
3300 return( FALSE );
3301 if( detachedSig && hashContext != CRYPT_UNUSED )
3302 {
3303 /* The hash value is being supplied externally, add it to the
3304 envelope before we add the signature data */
3305 status = cryptSetAttribute( cryptEnvelope,
3306 CRYPT_ENVINFO_DETACHEDSIGNATURE, TRUE );
3307 if( cryptStatusOK( status ) )
3308 status = cryptSetAttribute( cryptEnvelope, CRYPT_ENVINFO_HASH,
3309 hashContext );
3310 if( cryptStatusError( status ) )
3311 {
3312 printf( "Couldn't add externally-generated hash value to "
3313 "envelope, status %d, line %d.\n", status, __LINE__ );
3314 return( FALSE );
3315 }
3316 }
3317 count = pushData( cryptEnvelope, signedData, signedDataLength, NULL, 0 );
3318 if( count == CRYPT_ERROR_NOTAVAIL && \
3319 !( detachedSig || hasTimestamp || checkData ) )
3320 {
3321 /* Some old signed data uses deprecated or now-broken algorithms
3322 which will produce a CRYPT_ERROR_NOTAVAIL if we try and verify
3323 the signature, treat this as a special case */
3324 puts( "Warning: The hash/signature algorithm required to verify "
3325 "the signed data\n isn't enabled in this build of "
3326 "cryptlib, can't verify the\n signature." );
3327 if( !destroyEnvelope( cryptEnvelope ) )
3328 return( FALSE );
3329 return( TRUE );
3330 }
3331 if( !cryptStatusError( count ) )
3332 {
3333 if( detachedSig )
3334 {
3335 if( hashContext == CRYPT_UNUSED )
3336 {
3337 count = pushData( cryptEnvelope, ENVELOPE_TESTDATA,
3338 ENVELOPE_TESTDATA_SIZE, NULL, 0 );
3339 }
3340 }
3341 else
3342 count = popData( cryptEnvelope, globalBuffer, BUFFER_SIZE );
3343 }
3344 if( cryptStatusError( count ) )
3345 return( FALSE );
3346
3347 /* If we're checking for the ability to reject an incorrect key, fetch
3348 a bogus signature key and try and add that */
3349 if( checkWrongKey )
3350 {
3351 CRYPT_CERTIFICATE cryptWrongCert;
3352
3353 status = getPublicKey( &cryptWrongCert, DUAL_PRIVKEY_FILE,
3354 DUAL_SIGNKEY_LABEL );
3355 if( cryptStatusError( status ) )
3356 return( FALSE );
3357 status = cryptSetAttribute( cryptEnvelope, CRYPT_ENVINFO_SIGNATURE,
3358 cryptWrongCert );
3359 cryptDestroyCert( cryptWrongCert );
3360 if( status != CRYPT_ERROR_WRONGKEY )
3361 {
3362 printf( "Use of incorrect key wasn't detected, got %d, should "
3363 "have been %d, line %d.\n", status,
3364 CRYPT_ERROR_WRONGKEY, __LINE__ );
3365 return( FALSE );
3366 }
3367 }
3368
3369 /* Display the details of the envelope signature and check whether
3370 there's more information such as a timestamp or a second signature
3371 present */
3372 status = displaySigResult( cryptEnvelope, sigCheckContext,
3373 mustHaveAttributes, TRUE );
3374 if( status == TRUE && hasTimestamp )
3375 {
3376 CRYPT_ENVELOPE cryptTimestamp;
3377 int contentType;
3378
3379 /* Try and get the timestamp info. Note that we can't safely use
3380 displaySigResult() on every timestamp because many are stripped-
3381 down minimal-size CMS messages with no additional sig-checking
3382 info present (for those ones we have to stop at reading the CMS
3383 content-type to make sure that everything's OK), but for the
3384 cryptlib test TSA there's always a full CMS signed message
3385 returned */
3386 printf( "Envelope contains a timestamp..." );
3387 status = cryptGetAttribute( cryptEnvelope, CRYPT_ENVINFO_TIMESTAMP,
3388 &cryptTimestamp );
3389 if( cryptStatusError( status ) )
3390 {
3391 printf( "\nCouldn't read timestamp from envelope, status %d, "
3392 "line %d.\n", status, __LINE__ );
3393 return( FALSE );
3394 }
3395 status = cryptGetAttribute( cryptTimestamp,
3396 CRYPT_ENVINFO_CONTENTTYPE, &contentType );
3397 if( cryptStatusError( status ) || \
3398 contentType != CRYPT_CONTENT_TSTINFO )
3399 {
3400 printf( "\nTimestamp data envelope doesn't appear to contain a "
3401 "timestamp, line %d.\n", __LINE__ );
3402 return( FALSE );
3403 }
3404 puts( " timestamp data appears OK." );
3405
3406 /* Now get the signature info (if the timestamp doesn't contain a
3407 full CMS message then we'd set 'status = TRUE' at this point
3408 without performing the signture check) */
3409 puts( "Timestamp signature information is:" );
3410 status = displaySigResult( cryptTimestamp, sigCheckContext,
3411 TRUE, TRUE );
3412 cryptDestroyEnvelope( cryptTimestamp );
3413 }
3414 if( status == TRUE && cryptStatusOK( \
3415 cryptSetAttribute( cryptEnvelope, CRYPT_ATTRIBUTE_CURRENT_GROUP,
3416 CRYPT_CURSOR_NEXT ) ) )
3417 {
3418 puts( "Data has a second signature:" );
3419 status = displaySigResult( cryptEnvelope, CRYPT_UNUSED,
3420 mustHaveAttributes, FALSE );
3421 }
3422 if( status == TRUE && cryptStatusOK( \
3423 cryptSetAttribute( cryptEnvelope, CRYPT_ATTRIBUTE_CURRENT_GROUP,
3424 CRYPT_CURSOR_NEXT ) ) )
3425 {
3426 /* We can have two, but not three */
3427 printf( "Data appears to have (nonexistent) third signature, "
3428 "line %d.\n", __LINE__ );
3429 return( FALSE );
3430 }
3431
3432 /* If we're testing the ability to handle reference-counted objects,
3433 create multiple references to the certificate object in the signed
3434 data and make sure they're accessible */
3435 if( testRefCount )
3436 {
3437 CRYPT_CERTIFICATE cryptCert1, cryptCert2, cryptCert3;
3438 int value;
3439
3440 /* Create three references to the signing certificate */
3441 status = cryptGetAttribute( cryptEnvelope, CRYPT_ENVINFO_SIGNATURE,
3442 &cryptCert1 );
3443 if( cryptStatusOK( status ) )
3444 status = cryptGetAttribute( cryptEnvelope, CRYPT_ENVINFO_SIGNATURE,
3445 &cryptCert2 );
3446 if( cryptStatusOK( status ) )
3447 status = cryptGetAttribute( cryptEnvelope, CRYPT_ENVINFO_SIGNATURE,
3448 &cryptCert3 );
3449 if( cryptStatusError( status ) )
3450 {
3451 printf( "Couldn't retrieve 3 copies of signing certificate from "
3452 "envelope, line %d.\n", __LINE__ );
3453 return( FALSE );
3454 }
3455 if( cryptCert1 != cryptCert2 || cryptCert1 != cryptCert3 )
3456 {
3457 printf( "Multiple-referenced object has different object "
3458 "handles, line %d.\n", __LINE__ );
3459 return( FALSE );
3460 }
3461
3462 /* Destroy the second reference and make sure that it's still
3463 accessible via both itself and another reference */
3464 status = cryptDestroyCert( cryptCert2 );
3465 if( cryptStatusOK( status ) )
3466 {
3467 status = cryptGetAttribute( cryptCert2, CRYPT_CERTINFO_CERTTYPE,
3468 &value );
3469 }
3470 if( cryptStatusOK( status ) )
3471 {
3472 status = cryptGetAttribute( cryptCert1, CRYPT_CERTINFO_CERTTYPE,
3473 &value );
3474 }
3475 if( cryptStatusError( status ) )
3476 {
3477 printf( "Removing signing certificate reference caused "
3478 "consistency failure, line %d.\n", __LINE__ );
3479 return( FALSE );
3480 }
3481
3482 /* Destroy the original reference and make sure that it's no longer
3483 accessible but other references are */
3484 status = cryptDestroyCert( cryptCert1 );
3485 if( cryptStatusOK( status ) )
3486 {
3487 status = cryptGetAttribute( cryptCert1, CRYPT_CERTINFO_CERTTYPE,
3488 &value );
3489 }
3490 if( cryptStatusOK( status ) )
3491 {
3492 status = cryptGetAttribute( cryptCert3, CRYPT_CERTINFO_CERTTYPE,
3493 &value );
3494 }
3495 if( cryptStatusError( status ) )
3496 {
3497 printf( "Removing signing certificate reference caused "
3498 "consistency failure, line %d.\n", __LINE__ );
3499 return( FALSE );
3500 }
3501
3502 /* Destroy the last reference and make sure that it's now
3503 inaccessible */
3504 status = cryptDestroyCert( cryptCert1 );
3505 if( cryptStatusOK( status ) )
3506 {
3507 status = cryptGetAttribute( cryptCert1, CRYPT_CERTINFO_CERTTYPE,
3508 &value );
3509 status = cryptStatusError( status ) ? \
3510 CRYPT_OK : CRYPT_ERROR_FAILED;
3511 }
3512 if( cryptStatusError( status ) )
3513 {
3514 printf( "Removing signing certificate reference caused "
3515 "consistency failure, line %d.\n", __LINE__ );
3516 return( FALSE );
3517 }
3518
3519 /* Remember that everything went OK */
3520 status = TRUE;
3521 }
3522
3523 /* Make sure that the result matches what we pushed */
3524 if( !detachedSig && checkData && \
3525 !compareData( ENVELOPE_TESTDATA, ENVELOPE_TESTDATA_SIZE, \
3526 globalBuffer, count ) )
3527 return( FALSE );
3528
3529 /* Clean up */
3530 if( !destroyEnvelope( cryptEnvelope ) )
3531 return( FALSE );
3532 return( status );
3533 }
3534
cmsEnvelopeSign(const BOOLEAN useDatasize,const BOOLEAN useAttributes,const BOOLEAN useExtAttributes,const BOOLEAN detachedSig,const int externalHashLevel,const BOOLEAN useTimestamp,const BOOLEAN useNonDataContent,const BOOLEAN dualSig,const BOOLEAN testRefCount,const CRYPT_CONTEXT externalSignContext,const CRYPT_FORMAT_TYPE formatType)3535 static int cmsEnvelopeSign( const BOOLEAN useDatasize,
3536 const BOOLEAN useAttributes, const BOOLEAN useExtAttributes,
3537 const BOOLEAN detachedSig, const int externalHashLevel,
3538 const BOOLEAN useTimestamp, const BOOLEAN useNonDataContent,
3539 const BOOLEAN dualSig, const BOOLEAN testRefCount,
3540 const CRYPT_CONTEXT externalSignContext,
3541 const CRYPT_FORMAT_TYPE formatType )
3542 {
3543 CRYPT_ENVELOPE cryptEnvelope;
3544 CRYPT_CONTEXT cryptContext, cryptContext2, hashContext = CRYPT_UNUSED;
3545 BOOLEAN isPGP = ( formatType == CRYPT_FORMAT_PGP ) ? TRUE : FALSE;
3546 BOOLEAN isRawCMS = ( formatType == CRYPT_FORMAT_CRYPTLIB ) ? TRUE : FALSE;
3547 int count, status = CRYPT_OK;
3548
3549 if( !keyReadOK )
3550 {
3551 puts( "Couldn't find key files, skipping test of CMS signed "
3552 "enveloping..." );
3553 return( TRUE );
3554 }
3555 printf( "Testing %s %s%s", isPGP ? "PGP" : "CMS",
3556 useExtAttributes ? "extended " : "",
3557 detachedSig ? "detached signature" : \
3558 dualSig ? "dual signature" : "signed enveloping" );
3559 if( useNonDataContent )
3560 printf( " of non-data content" );
3561 if( testRefCount )
3562 printf( " for reference-count capability check" );
3563 if( externalHashLevel )
3564 {
3565 printf( ( externalHashLevel == 1 ) ? \
3566 " with externally-supplied hash for verify" : \
3567 " with ext-supplied hash for sign and verify" );
3568 }
3569 if( !isPGP && !( useAttributes || testRefCount ) )
3570 printf( " without signing attributes" );
3571 if( useDatasize && \
3572 !( useNonDataContent || useAttributes || useExtAttributes || \
3573 detachedSig || useTimestamp || testRefCount ) )
3574 {
3575 /* Keep the amount of stuff being printed down */
3576 printf( " with datasize hint" );
3577 }
3578 if( useTimestamp )
3579 printf( " and timestamp" );
3580 puts( "..." );
3581
3582 /* Get the private key. If we're applying two signatures, we also get
3583 a second signing key. Since the dual-key file test has created a
3584 second signing key, we use that as the most convenient one */
3585 if( externalSignContext != CRYPT_UNUSED )
3586 cryptContext = externalSignContext;
3587 else
3588 {
3589 status = getPrivateKey( &cryptContext, USER_PRIVKEY_FILE,
3590 USER_PRIVKEY_LABEL, TEST_PRIVKEY_PASSWORD );
3591 if( cryptStatusError( status ) )
3592 {
3593 puts( "Read of private key from key file failed, cannot test "
3594 "CMS enveloping." );
3595 return( FALSE );
3596 }
3597 }
3598 if( dualSig )
3599 {
3600 status = getPrivateKey( &cryptContext2, DUAL_PRIVKEY_FILE,
3601 DUAL_SIGNKEY_LABEL, TEST_PRIVKEY_PASSWORD );
3602 if( cryptStatusError( status ) )
3603 {
3604 puts( "Read of private key from key file failed, cannot test "
3605 "CMS enveloping." );
3606 return( FALSE );
3607 }
3608 }
3609
3610 /* If we're supplying the hash value for signing externally, calculate
3611 it now */
3612 if( externalHashLevel > 1 )
3613 {
3614 int hashAlgo;
3615
3616 status = cryptGetAttribute( CRYPT_UNUSED, CRYPT_OPTION_ENCR_HASH,
3617 &hashAlgo );
3618 if( cryptStatusOK( status ) )
3619 status = cryptCreateContext( &hashContext, CRYPT_UNUSED,
3620 hashAlgo );
3621 if( cryptStatusOK( status ) )
3622 status = cryptEncrypt( hashContext, ENVELOPE_TESTDATA,
3623 ENVELOPE_TESTDATA_SIZE );
3624 if( cryptStatusOK( status ) && formatType == CRYPT_FORMAT_CMS )
3625 status = cryptEncrypt( hashContext, "", 0 );
3626 if( cryptStatusError( status ) )
3627 {
3628 puts( "Couldn't create external hash of data." );
3629 return( FALSE );
3630 }
3631 }
3632
3633 /* Create the CMS envelope and push in the signing key(s) and data */
3634 if( !createEnvelope( &cryptEnvelope, formatType ) )
3635 return( FALSE );
3636 if( !addEnvInfoNumeric( cryptEnvelope, CRYPT_ENVINFO_SIGNATURE,
3637 cryptContext ) )
3638 return( FALSE );
3639 if( dualSig )
3640 {
3641 if( !addEnvInfoNumeric( cryptEnvelope, CRYPT_ENVINFO_SIGNATURE,
3642 cryptContext2 ) )
3643 return( FALSE );
3644 }
3645 if( detachedSig )
3646 {
3647 if( !addEnvInfoNumeric( cryptEnvelope,
3648 CRYPT_ENVINFO_DETACHEDSIGNATURE, TRUE ) )
3649 return( FALSE );
3650 }
3651 if( externalHashLevel > 1 )
3652 {
3653 if( !addEnvInfoNumeric( cryptEnvelope, CRYPT_ENVINFO_HASH,
3654 hashContext ) )
3655 return( FALSE );
3656 }
3657 if( ( externalSignContext == CRYPT_UNUSED ) && !isPGP && !isRawCMS )
3658 cryptDestroyContext( cryptContext );
3659 if( dualSig )
3660 cryptDestroyContext( cryptContext2 );
3661 if( externalHashLevel > 1 )
3662 {
3663 cryptDestroyContext( hashContext );
3664 hashContext = CRYPT_UNUSED;
3665 }
3666 if( useNonDataContent )
3667 {
3668 /* Test non-data content type w.automatic attribute handling */
3669 status = cryptSetAttribute( cryptEnvelope, CRYPT_ENVINFO_CONTENTTYPE,
3670 CRYPT_CONTENT_SIGNEDDATA );
3671 }
3672 if( cryptStatusOK( status ) && useDatasize )
3673 status = cryptSetAttribute( cryptEnvelope, CRYPT_ENVINFO_DATASIZE,
3674 ENVELOPE_TESTDATA_SIZE );
3675 if( cryptStatusOK( status ) && useExtAttributes )
3676 {
3677 /* We have to be careful when setting CMS attributes because most
3678 are never used by anything so they're only available of use of
3679 obscure attributes is enabled (unfortunately there aren't
3680 actually any attributes that are available for this, but the
3681 functionality is tested by the added-by-default attributes such
3682 as the signing time) */
3683 #ifdef USE_CMS_OBSCURE
3684 CRYPT_CERTIFICATE cmsAttributes;
3685
3686 /* Add an ESS security label and signing description as signing
3687 attributes */
3688 status = cryptCreateCert( &cmsAttributes, CRYPT_UNUSED,
3689 CRYPT_CERTTYPE_CMS_ATTRIBUTES );
3690 if( cryptStatusError( status ) )
3691 return( FALSE );
3692 status = cryptSetAttributeString( cmsAttributes,
3693 CRYPT_CERTINFO_CMS_SECLABEL_POLICY,
3694 TEXT( "1 3 6 1 4 1 9999 1" ),
3695 paramStrlen( TEXT( "1 3 6 1 4 1 9999 1" ) ) );
3696 if( cryptStatusOK( status ) )
3697 status = cryptSetAttribute( cmsAttributes,
3698 CRYPT_CERTINFO_CMS_SECLABEL_CLASSIFICATION,
3699 CRYPT_CLASSIFICATION_SECRET );
3700 if( cryptStatusOK( status ) )
3701 status = cryptSetAttributeString( cmsAttributes,
3702 CRYPT_CERTINFO_CMS_SECLABEL_CATTYPE,
3703 TEXT( "1 3 6 1 4 1 9999 2" ),
3704 paramStrlen( TEXT( "1 3 6 1 4 1 9999 2" ) ) );
3705 if( cryptStatusOK( status ) )
3706 status = cryptSetAttributeString( cmsAttributes,
3707 CRYPT_CERTINFO_CMS_SECLABEL_CATVALUE,
3708 "\x04\x04\x01\x02\x03\x04", 6 );
3709 if( cryptStatusOK( status ) )
3710 status = cryptSetAttributeString( cmsAttributes,
3711 CRYPT_CERTINFO_CMS_SIGNINGDESCRIPTION,
3712 "This signature isn't worth the paper it's not "
3713 "printed on", 56 );
3714 if( cryptStatusOK( status ) )
3715 status = cryptSetAttribute( cryptEnvelope,
3716 CRYPT_ENVINFO_SIGNATURE_EXTRADATA, cmsAttributes );
3717 cryptDestroyCert( cmsAttributes );
3718 #endif /* USE_CMS_OBSCURE */
3719 }
3720 if( cryptStatusOK( status ) && !isPGP && !useAttributes )
3721 status = cryptSetAttribute( CRYPT_UNUSED,
3722 CRYPT_OPTION_CMS_DEFAULTATTRIBUTES, FALSE );
3723 if( cryptStatusOK( status ) && useTimestamp )
3724 {
3725 CRYPT_SESSION cryptSession;
3726
3727 /* Create the TSP session, add the TSA URL, and add it to the
3728 envelope */
3729 status = cryptCreateSession( &cryptSession, CRYPT_UNUSED,
3730 CRYPT_SESSION_TSP );
3731 if( status == CRYPT_ERROR_PARAM3 ) /* TSP session access not available */
3732 return( CRYPT_ERROR_NOTAVAIL );
3733 status = cryptSetAttributeString( cryptSession,
3734 CRYPT_SESSINFO_SERVER_NAME,
3735 TSP_DEFAULTSERVER_NAME,
3736 paramStrlen( TSP_DEFAULTSERVER_NAME ) );
3737 if( cryptStatusError( status ) )
3738 return( attrErrorExit( cryptSession, "cryptSetAttributeString()",
3739 status, __LINE__ ) );
3740 status = cryptSetAttribute( cryptEnvelope, CRYPT_ENVINFO_TIMESTAMP,
3741 cryptSession );
3742 cryptDestroySession( cryptSession );
3743 if( isRawCMS )
3744 {
3745 /* Signing attributes aren't allowed for raw CMS data */
3746 cryptDestroyContext( cryptContext );
3747 destroyEnvelope( cryptEnvelope );
3748 if( cryptStatusOK( status ) )
3749 {
3750 printf( "Addition of timestamping attribute to "
3751 "CRYPT_FORMAT_CRYPTLIB envelope\nsucceeded, should "
3752 "have failed, line %d.\n", __LINE__ );
3753 return( FALSE );
3754 }
3755 puts( "Enveloping with timestamp using invalid env.type was "
3756 "correctly rejected.\n" );
3757 return( TRUE );
3758 }
3759 }
3760 if( cryptStatusError( status ) )
3761 {
3762 printf( "cryptSetAttribute() failed with error code %d, line %d.\n",
3763 status, __LINE__ );
3764 return( FALSE );
3765 }
3766
3767 /* Push in the data to be signed, unless it's already been processed via
3768 an external hash */
3769 if( externalHashLevel < 2 )
3770 {
3771 status = pushData( cryptEnvelope, ENVELOPE_TESTDATA,
3772 ENVELOPE_TESTDATA_SIZE, NULL, 0 );
3773 }
3774 if( !isPGP && !useAttributes )
3775 {
3776 /* Restore the default attributes setting */
3777 cryptSetAttribute( CRYPT_UNUSED, CRYPT_OPTION_CMS_DEFAULTATTRIBUTES,
3778 TRUE );
3779 }
3780 if( cryptStatusError( status ) )
3781 {
3782 /* The timestamping can fail for a wide range of (non-fatal) reasons,
3783 typically either because this build doesn't have networking
3784 enabled or because the TSA can't be contacted, so we don't treat
3785 this one as a fatal error */
3786 if( useTimestamp )
3787 {
3788 puts( "Envelope timestamping failed due to problems talking to "
3789 "TSA, this is a non-\ncritical problem. Continuing...\n" );
3790 cryptDestroyEnvelope( cryptEnvelope );
3791 return( TRUE );
3792 }
3793 return( FALSE );
3794 }
3795
3796 /* Pop the resulting signature data and destroy the envelope */
3797 count = popData( cryptEnvelope, globalBuffer, BUFFER_SIZE );
3798 if( cryptStatusError( count ) )
3799 return( FALSE );
3800 if( !destroyEnvelope( cryptEnvelope ) )
3801 return( FALSE );
3802
3803 /* Tell them what happened */
3804 printf( "%s %s has size %d bytes.\n", isPGP ? "PGP" : "CMS",
3805 ( detachedSig ) ? "detached signature" : "signed data",
3806 count );
3807 debugDump( detachedSig ?
3808 ( !isPGP ? \
3809 ( useDatasize ? "smi_dsg" : "smi_dsgn" ) : \
3810 "pgp_dsg.pgp" ) : \
3811 useExtAttributes ? \
3812 ( useDatasize ? "smi_esg" : "smi_esgn" ) : \
3813 useTimestamp ? \
3814 ( useDatasize ? "smi_tsg" : "smi_tsgn" ) : \
3815 useNonDataContent ? \
3816 ( useDatasize ? "smi_ndc" : "smi_ndcn" ) : \
3817 dualSig ? \
3818 ( useDatasize ? "smi_2sg" : "smi_n2sg" ) : \
3819 useDatasize ? "smi_sig" : "smi_sign", globalBuffer, count );
3820
3821 /* If we're supplying the hash value for verification externally,
3822 calculate it now */
3823 if( externalHashLevel > 0 )
3824 {
3825 int hashAlgo;
3826
3827 status = cryptGetAttribute( CRYPT_UNUSED, CRYPT_OPTION_ENCR_HASH,
3828 &hashAlgo );
3829 if( cryptStatusOK( status ) )
3830 status = cryptCreateContext( &hashContext, CRYPT_UNUSED,
3831 hashAlgo );
3832 if( cryptStatusOK( status ) )
3833 status = cryptEncrypt( hashContext, ENVELOPE_TESTDATA,
3834 ENVELOPE_TESTDATA_SIZE );
3835 if( cryptStatusOK( status ) && formatType == CRYPT_FORMAT_CMS )
3836 status = cryptEncrypt( hashContext, "", 0 );
3837 if( cryptStatusError( status ) )
3838 {
3839 puts( "Couldn't create external hash of data." );
3840 return( FALSE );
3841 }
3842 }
3843
3844 /* Make sure that the signature is valid. The somewhat redundant mapping
3845 of useNonDataContent is because we're performing an additional check
3846 of envelope key-handling as part of this particular operation */
3847 status = cmsEnvelopeSigCheck( globalBuffer, count,
3848 isPGP || isRawCMS ? cryptContext : CRYPT_UNUSED,
3849 hashContext, detachedSig, useTimestamp, TRUE,
3850 useAttributes, useNonDataContent ? TRUE : FALSE,
3851 testRefCount );
3852 if( externalHashLevel > 0 )
3853 cryptDestroyContext( hashContext );
3854 if( isPGP || isRawCMS )
3855 cryptDestroyContext( cryptContext );
3856 if( status <= 0 )
3857 return( FALSE );
3858
3859 if( detachedSig )
3860 {
3861 printf( "Creation of %s %sdetached signature %ssucceeded.\n\n",
3862 isPGP ? "PGP" : "CMS", useExtAttributes ? "extended " : "",
3863 ( hashContext != CRYPT_UNUSED ) ? \
3864 "with externally-supplied hash " : "" );
3865 }
3866 else
3867 {
3868 printf( "Enveloping of CMS %s%ssigned data succeeded.\n\n",
3869 useExtAttributes ? "extended " : "",
3870 useTimestamp ? "timestamped " : "" );
3871 }
3872 return( TRUE );
3873 }
3874
testCMSEnvelopeSign(void)3875 int testCMSEnvelopeSign( void )
3876 {
3877 if( !cmsEnvelopeSign( FALSE, FALSE, FALSE, FALSE, 0, FALSE, FALSE, FALSE, FALSE, CRYPT_UNUSED, CRYPT_FORMAT_CMS ) )
3878 return( FALSE ); /* Minimal (no default S/MIME attributes) */
3879 if( !cmsEnvelopeSign( FALSE, TRUE, FALSE, FALSE, 0, FALSE, FALSE, FALSE, FALSE, CRYPT_UNUSED, CRYPT_FORMAT_CMS ) )
3880 return( FALSE ); /* Standard (default S/MIME signing attributes) */
3881 if( !cmsEnvelopeSign( TRUE, TRUE, FALSE, FALSE, 0, FALSE, FALSE, FALSE, FALSE, CRYPT_UNUSED, CRYPT_FORMAT_CMS ) )
3882 return( FALSE ); /* Datasize and attributes */
3883 if( !cmsEnvelopeSign( FALSE, TRUE, TRUE, FALSE, 0, FALSE, FALSE, FALSE, FALSE, CRYPT_UNUSED, CRYPT_FORMAT_CMS ) )
3884 return( FALSE ); /* Extended signing attributes */
3885 if( !cmsEnvelopeSign( TRUE, TRUE, TRUE, FALSE, 0, FALSE, FALSE, FALSE, FALSE, CRYPT_UNUSED, CRYPT_FORMAT_CMS ) )
3886 return( FALSE ); /* Datasize and extended attributes */
3887 return( cmsEnvelopeSign( TRUE, TRUE, FALSE, FALSE, 0, FALSE, TRUE, FALSE, FALSE, CRYPT_UNUSED, CRYPT_FORMAT_CMS ) );
3888 } /* Signing of non-data content */
3889
testCMSEnvelopeDualSign(void)3890 int testCMSEnvelopeDualSign( void )
3891 {
3892 return( cmsEnvelopeSign( TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, FALSE, CRYPT_UNUSED, CRYPT_FORMAT_CMS ) );
3893 /* Standard, with two signatures */
3894 }
3895
testCMSEnvelopeDetachedSig(void)3896 int testCMSEnvelopeDetachedSig( void )
3897 {
3898 if( !cmsEnvelopeSign( FALSE, TRUE, FALSE, TRUE, 0, FALSE, FALSE, FALSE, FALSE, CRYPT_UNUSED, CRYPT_FORMAT_CMS ) )
3899 return( FALSE ); /* Detached sig and attributes */
3900 if( !cmsEnvelopeSign( FALSE, TRUE, FALSE, TRUE, 1, FALSE, FALSE, FALSE, FALSE, CRYPT_UNUSED, CRYPT_FORMAT_CMS ) )
3901 return( FALSE ); /* Detached sig, attributes, externally-suppl.hash for verify */
3902 if( !cmsEnvelopeSign( FALSE, TRUE, FALSE, TRUE, 2, FALSE, FALSE, FALSE, FALSE, CRYPT_UNUSED, CRYPT_FORMAT_CMS ) )
3903 return( FALSE ); /* Detached sig, externally-suppl.hash for sign and verify */
3904 if( !cmsEnvelopeSign( TRUE, FALSE, FALSE, TRUE, 1, FALSE, FALSE, FALSE, FALSE, CRYPT_UNUSED, CRYPT_FORMAT_PGP ) )
3905 return( FALSE ); /* Detached sig, data size, externally-suppl.hash for verify, PGP format */
3906 return( cmsEnvelopeSign( TRUE, FALSE, FALSE, TRUE, 2, FALSE, FALSE, FALSE, FALSE, CRYPT_UNUSED, CRYPT_FORMAT_PGP ) );
3907 } /* Detached sig, data size, externally-suppl.hash for sign and verify, PGP format */
3908
testCMSEnvelopeSignEx(const CRYPT_CONTEXT signContext)3909 int testCMSEnvelopeSignEx( const CRYPT_CONTEXT signContext )
3910 {
3911 return( cmsEnvelopeSign( TRUE, TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, signContext, CRYPT_FORMAT_CMS ) );
3912 } /* Datasize, attributes, external signing context */
3913
testCMSEnvelopeRefCount(void)3914 int testCMSEnvelopeRefCount( void )
3915 {
3916 /* This isn't so much a signature test as a test of the reference-
3917 counting mechanism in the cryptlib kernel, but it uses a CMS
3918 signature with associated certificate data for the test */
3919 return( cmsEnvelopeSign( TRUE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, TRUE, CRYPT_UNUSED, CRYPT_FORMAT_CMS ) );
3920 }
3921
testSessionEnvTSP(void)3922 int testSessionEnvTSP( void )
3923 {
3924 /* This is a pseudo-enveloping test that uses the enveloping
3925 functionality but is called as part of the session tests since full
3926 testing of the TSP handling requires that it be used to timestamp an
3927 S/MIME sig */
3928 if( !cmsEnvelopeSign( TRUE, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, CRYPT_UNUSED, CRYPT_FORMAT_CMS ) )
3929 return( FALSE ); /* Datasize, attributes, timestamp */
3930 return( cmsEnvelopeSign( TRUE, TRUE, FALSE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE, CRYPT_UNUSED, CRYPT_FORMAT_CRYPTLIB ) );
3931 } /* Invalid attempt to use attrs.with raw CMS envelope */
3932
cmsImportSignedData(const char * fileName,const int fileNo)3933 static int cmsImportSignedData( const char *fileName, const int fileNo )
3934 {
3935 BYTE *bufPtr = globalBuffer;
3936 char msgBuffer[ 128 ];
3937 int count, status;
3938
3939 /* Read the test data */
3940 count = getFileSize( fileName ) + 10;
3941 if( count >= BUFFER_SIZE )
3942 {
3943 if( ( bufPtr = malloc( count ) ) == NULL )
3944 {
3945 printf( "Couldn't allocate test buffer of %d bytes, line %d.\n",
3946 count, __LINE__ );
3947 return( FALSE );
3948 }
3949 }
3950 sprintf( msgBuffer, "S/MIME SignedData #%d", fileNo );
3951 count = readFileData( fileName, msgBuffer, bufPtr, count, 2048, FALSE );
3952 if( count <= 0 )
3953 {
3954 if( bufPtr != globalBuffer )
3955 free( bufPtr );
3956 return( count );
3957 }
3958
3959 /* Check the signature on the data */
3960 status = cmsEnvelopeSigCheck( bufPtr, count, CRYPT_UNUSED, CRYPT_UNUSED,
3961 FALSE, FALSE, FALSE,
3962 ( fileNo == 1 ) ? FALSE : TRUE, FALSE, FALSE );
3963 if( bufPtr != globalBuffer )
3964 free( bufPtr );
3965 if( status )
3966 puts( "S/MIME SignedData import succeeded.\n" );
3967 else
3968 {
3969 /* The AuthentiCode data sig-check fails for some reason */
3970 if( fileNo == 2 )
3971 {
3972 puts( "AuthentiCode SignedData import succeeded but signature "
3973 "couldn't be verified\n due to AuthentiCode special "
3974 "processing requirements.\n" );
3975 }
3976 }
3977 return( status );
3978 }
3979
3980 /* Test CMS enveloping/de-enveloping */
3981
cmsEnvelopeDecrypt(const void * envelopedData,const int envelopedDataLength,const CRYPT_HANDLE externalKeyset,const C_STR externalPassword,const BOOLEAN checkDataMatch)3982 static int cmsEnvelopeDecrypt( const void *envelopedData,
3983 const int envelopedDataLength,
3984 const CRYPT_HANDLE externalKeyset,
3985 const C_STR externalPassword,
3986 const BOOLEAN checkDataMatch )
3987 {
3988 CRYPT_ENVELOPE cryptEnvelope;
3989 int count, status;
3990
3991 /* Create the envelope and push in the decryption keyset */
3992 if( !createDeenvelope( &cryptEnvelope ) )
3993 return( FALSE );
3994 if( externalKeyset != CRYPT_UNUSED )
3995 status = addEnvInfoNumeric( cryptEnvelope,
3996 CRYPT_ENVINFO_KEYSET_DECRYPT, externalKeyset );
3997 else
3998 {
3999 CRYPT_KEYSET cryptKeyset;
4000
4001 status = cryptKeysetOpen( &cryptKeyset, CRYPT_UNUSED,
4002 CRYPT_KEYSET_FILE, USER_PRIVKEY_FILE,
4003 CRYPT_KEYOPT_READONLY );
4004 if( cryptStatusOK( status ) )
4005 status = addEnvInfoNumeric( cryptEnvelope,
4006 CRYPT_ENVINFO_KEYSET_DECRYPT, cryptKeyset );
4007 cryptKeysetClose( cryptKeyset );
4008 }
4009 if( status <= 0 )
4010 return( FALSE );
4011
4012 /* Push in the data */
4013 if( externalPassword == NULL )
4014 externalPassword = TEST_PRIVKEY_PASSWORD;
4015 count = pushData( cryptEnvelope, envelopedData, envelopedDataLength,
4016 externalPassword, paramStrlen( externalPassword ) );
4017 if( cryptStatusError( count ) )
4018 return( FALSE );
4019 count = popData( cryptEnvelope, globalBuffer, BUFFER_SIZE );
4020 if( cryptStatusError( count ) )
4021 return( FALSE );
4022 if( !destroyEnvelope( cryptEnvelope ) )
4023 return( FALSE );
4024
4025 /* If we're not checking for a match of the decrypted data (done when
4026 the data is coming from an external source rather than being
4027 something that we generated ourselves), we're done */
4028 if( !checkDataMatch )
4029 return( TRUE );
4030
4031 /* Make sure that the result matches what we pushed */
4032 if( !compareData( ENVELOPE_TESTDATA, ENVELOPE_TESTDATA_SIZE,
4033 globalBuffer, count ) )
4034 return( FALSE );
4035
4036 return( TRUE );
4037 }
4038
cmsEnvelopeCrypt(const char * dumpFileName,const BOOLEAN useDatasize,const BOOLEAN useStreamCipher,const BOOLEAN useLargeBlockCipher,const BOOLEAN useExternalRecipientKeyset,const CRYPT_HANDLE externalCryptContext,const CRYPT_HANDLE externalKeyset,const C_STR externalPassword,const C_STR recipientName)4039 static int cmsEnvelopeCrypt( const char *dumpFileName,
4040 const BOOLEAN useDatasize,
4041 const BOOLEAN useStreamCipher,
4042 const BOOLEAN useLargeBlockCipher,
4043 const BOOLEAN useExternalRecipientKeyset,
4044 const CRYPT_HANDLE externalCryptContext,
4045 const CRYPT_HANDLE externalKeyset,
4046 const C_STR externalPassword,
4047 const C_STR recipientName )
4048 {
4049 CRYPT_ENVELOPE cryptEnvelope;
4050 CRYPT_HANDLE cryptKey;
4051 int count, status;
4052
4053 if( !keyReadOK )
4054 {
4055 puts( "Couldn't find key files, skipping test of CMS encrypted "
4056 "enveloping..." );
4057 return( TRUE );
4058 }
4059 printf( "Testing CMS public-key encrypted enveloping" );
4060 if( externalKeyset != CRYPT_UNUSED && recipientName != NULL )
4061 {
4062 if( useExternalRecipientKeyset )
4063 printf( " with recipient keys in device" );
4064 else
4065 printf( " with dual encr./signing certs" );
4066 }
4067 else
4068 {
4069 if( useStreamCipher )
4070 printf( " with stream cipher" );
4071 else
4072 {
4073 if( useLargeBlockCipher )
4074 printf( " with large block size cipher" );
4075 else
4076 {
4077 if( useDatasize )
4078 printf( " with datasize hint" );
4079 }
4080 }
4081 }
4082 puts( "..." );
4083
4084 /* Get the public key. We use assorted variants to make sure that they
4085 all work */
4086 if( externalCryptContext != CRYPT_UNUSED )
4087 {
4088 int cryptAlgo;
4089
4090 status = cryptGetAttribute( externalCryptContext, CRYPT_CTXINFO_ALGO,
4091 &cryptAlgo );
4092 if( cryptStatusError( status ) )
4093 {
4094 puts( "Couldn't determine algorithm for public key, cannot test "
4095 "CMS enveloping." );
4096 return( FALSE );
4097 }
4098 cryptKey = externalCryptContext;
4099 }
4100 else
4101 {
4102 if( recipientName == NULL )
4103 {
4104 /* No recipient name, get the public key */
4105 status = getPublicKey( &cryptKey, USER_PRIVKEY_FILE,
4106 USER_PRIVKEY_LABEL );
4107 if( cryptStatusError( status ) )
4108 return( FALSE );
4109 }
4110 }
4111
4112 /* Create the envelope, add the public key and originator key if
4113 necessary, push in the data, pop the enveloped result, and destroy
4114 the envelope */
4115 if( !createEnvelope( &cryptEnvelope, CRYPT_FORMAT_CMS ) )
4116 return( FALSE );
4117 if( recipientName != NULL )
4118 {
4119 CRYPT_KEYSET cryptKeyset = externalKeyset;
4120
4121 /* We're using a recipient name, add the recipient keyset and
4122 recipient name */
4123 if( !useExternalRecipientKeyset )
4124 {
4125 status = cryptKeysetOpen( &cryptKeyset, CRYPT_UNUSED,
4126 DATABASE_KEYSET_TYPE,
4127 DATABASE_KEYSET_NAME,
4128 CRYPT_KEYOPT_READONLY );
4129 if( cryptStatusError( status ) )
4130 {
4131 printf( "Couldn't open key database, status %d, line %d.\n",
4132 status, __LINE__ );
4133 return( FALSE );
4134 }
4135 }
4136 if( !addEnvInfoNumeric( cryptEnvelope, CRYPT_ENVINFO_KEYSET_ENCRYPT,
4137 cryptKeyset ) )
4138 return( FALSE );
4139 if( !useExternalRecipientKeyset )
4140 cryptKeysetClose( cryptKeyset );
4141 if( !addEnvInfoString( cryptEnvelope, CRYPT_ENVINFO_RECIPIENT,
4142 recipientName, paramStrlen( recipientName ) ) )
4143 return( FALSE );
4144 }
4145 else
4146 {
4147 if( !addEnvInfoNumeric( cryptEnvelope, CRYPT_ENVINFO_PUBLICKEY,
4148 cryptKey ) )
4149 return( FALSE );
4150 }
4151 if( externalCryptContext == CRYPT_UNUSED && recipientName == NULL )
4152 cryptDestroyObject( cryptKey );
4153 if( useDatasize )
4154 cryptSetAttribute( cryptEnvelope, CRYPT_ENVINFO_DATASIZE,
4155 ENVELOPE_TESTDATA_SIZE );
4156 count = pushData( cryptEnvelope, ENVELOPE_TESTDATA,
4157 ENVELOPE_TESTDATA_SIZE, NULL, 0 );
4158 if( cryptStatusError( count ) )
4159 return( FALSE );
4160 count = popData( cryptEnvelope, globalBuffer, BUFFER_SIZE );
4161 if( cryptStatusError( count ) )
4162 return( FALSE );
4163 if( !destroyEnvelope( cryptEnvelope ) )
4164 return( FALSE );
4165
4166 /* Tell them what happened */
4167 printf( "Enveloped data has size %d bytes.\n", count );
4168 debugDump( dumpFileName, globalBuffer, count );
4169
4170 /* Make sure that the enveloped data is valid */
4171 status = cmsEnvelopeDecrypt( globalBuffer, count, externalKeyset,
4172 externalPassword, TRUE );
4173 if( status <= 0 ) /* Can be FALSE or an error code */
4174 return( FALSE );
4175
4176 /* Clean up */
4177 puts( "Enveloping of CMS public-key encrypted data succeeded.\n" );
4178 return( TRUE );
4179 }
4180
cmsImportEnvelopedData(const char * fileName,const int fileNo)4181 static int cmsImportEnvelopedData( const char *fileName, const int fileNo )
4182 {
4183 CRYPT_ENVELOPE cryptEnvelope;
4184 BYTE *bufPtr = globalBuffer;
4185 char msgBuffer[ 128 ];
4186 int count, bytesIn, byteCount = 0, status;
4187
4188 /* Read the test data */
4189 count = getFileSize( fileName ) + 10;
4190 if( count >= BUFFER_SIZE )
4191 {
4192 if( ( bufPtr = malloc( count ) ) == NULL )
4193 {
4194 printf( "Couldn't allocate test buffer of %d bytes, lin e%d.\n",
4195 count, __LINE__ );
4196 return( FALSE );
4197 }
4198 }
4199 sprintf( msgBuffer, "S/MIME EnvelopedData #%d", fileNo );
4200 count = readFileData( fileName, msgBuffer, bufPtr, count, 128, FALSE );
4201 if( count <= 0 )
4202 {
4203 if( bufPtr != globalBuffer )
4204 free( bufPtr );
4205 return( count );
4206 }
4207
4208 /* Make sure that we can parse the data */
4209 if( !createDeenvelope( &cryptEnvelope ) )
4210 {
4211 if( bufPtr != globalBuffer )
4212 free( bufPtr );
4213 return( FALSE );
4214 }
4215 status = cryptPushData( cryptEnvelope, bufPtr, count, &bytesIn );
4216 while( status == CRYPT_ERROR_UNDERFLOW )
4217 {
4218 byteCount += bytesIn;
4219 status = cryptPushData( cryptEnvelope, bufPtr + byteCount,
4220 count - byteCount, &bytesIn );
4221 }
4222 if( bufPtr != globalBuffer )
4223 free( bufPtr );
4224 if( !destroyEnvelope( cryptEnvelope ) )
4225 return( FALSE );
4226 if( status == CRYPT_ENVELOPE_RESOURCE )
4227 {
4228 /* When we get to the CRYPT_ENVELOPE_RESOURCE stage we know that
4229 we've successfully processed all of the recipients, because
4230 cryptlib is asking us for a key to continue */
4231 status = CRYPT_OK;
4232 }
4233 if( cryptStatusError( status ) )
4234 {
4235 printf( "Couldn't de-envelope data, status = %d, line %d.\n",
4236 status, __LINE__ );
4237 return( FALSE );
4238 }
4239
4240 puts( "S/MIME EnvelopedData import succeeded.\n" );
4241 return( TRUE );
4242 }
4243
testCMSEnvelopePKCCrypt(void)4244 int testCMSEnvelopePKCCrypt( void )
4245 {
4246 int value, status;
4247
4248 if( !cmsEnvelopeCrypt( "smi_pkcn", FALSE, FALSE, FALSE, FALSE, CRYPT_UNUSED, CRYPT_UNUSED, NULL, NULL ) )
4249 return( FALSE ); /* Standard */
4250 if( !cmsEnvelopeCrypt( "smi_pkc", TRUE, FALSE, FALSE, FALSE, CRYPT_UNUSED, CRYPT_UNUSED, NULL, NULL ) )
4251 return( FALSE ); /* Datasize hint */
4252
4253 /* Test enveloping with an IV-less stream cipher, which bypasses the usual
4254 CBC-mode block cipher handling. The alternative way of doing this is
4255 to manually add a CRYPT_CTXINFO_SESSIONKEY object, doing it this way is
4256 less work */
4257 status = cryptGetAttribute( CRYPT_UNUSED, CRYPT_OPTION_ENCR_ALGO, &value );
4258 if( cryptStatusError( status ) )
4259 return( FALSE );
4260 cryptSetAttribute( CRYPT_UNUSED, CRYPT_OPTION_ENCR_ALGO, CRYPT_ALGO_RC4 );
4261 status = cmsEnvelopeCrypt( "smi_pkcs", TRUE, TRUE, FALSE, FALSE, CRYPT_UNUSED, CRYPT_UNUSED, NULL, NULL );
4262 cryptSetAttribute( CRYPT_UNUSED, CRYPT_OPTION_ENCR_ALGO, value );
4263 if( !status ) /* Datasize and stream cipher */
4264 return( status );
4265
4266 /* Test enveloping with a cipher with a larger-than-usual block size */
4267 status = cryptGetAttribute( CRYPT_UNUSED, CRYPT_OPTION_ENCR_ALGO, &value );
4268 if( cryptStatusError( status ) )
4269 return( FALSE );
4270 cryptSetAttribute( CRYPT_UNUSED, CRYPT_OPTION_ENCR_ALGO, CRYPT_ALGO_AES );
4271 status = cmsEnvelopeCrypt( "smi_pkcb", TRUE, FALSE, TRUE, FALSE, CRYPT_UNUSED, CRYPT_UNUSED, NULL, NULL );
4272 cryptSetAttribute( CRYPT_UNUSED, CRYPT_OPTION_ENCR_ALGO, value );
4273 return( status ); /* Datasize and large blocksize cipher */
4274 }
4275
testCMSEnvelopePKCCryptEx(const CRYPT_HANDLE encryptContext,const CRYPT_HANDLE decryptKeyset,const C_STR password,const C_STR recipient)4276 int testCMSEnvelopePKCCryptEx( const CRYPT_HANDLE encryptContext,
4277 const CRYPT_HANDLE decryptKeyset,
4278 const C_STR password, const C_STR recipient )
4279 {
4280 int status;
4281
4282 assert( ( encryptContext != CRYPT_UNUSED && recipient == NULL ) || \
4283 ( encryptContext == CRYPT_UNUSED && recipient != NULL ) );
4284
4285 /* We can either provide the recipient's key directly as a pubkey
4286 context or indirectly as a recipient name. This is used to test
4287 a device's ability to act as a recipient key store */
4288 status = cmsEnvelopeCrypt( "smi_pkcd", TRUE, FALSE, FALSE, \
4289 ( recipient != NULL ) ? TRUE : FALSE, \
4290 encryptContext, decryptKeyset, password, \
4291 recipient );
4292 if( status == CRYPT_ERROR_NOTFOUND )
4293 { /* Datasize, keys in crypto device */
4294 puts( " (This is probably because the public key certificate was "
4295 "regenerated after\n the certificate stored with the "
4296 "private key was created, so that the\n private key can't "
4297 "be identified any more using the public key that was\n "
4298 "used for encryption. This can happen when the cryptlib "
4299 "self-test is run\n in separate stages, with one stage "
4300 "re-using data that was created\n earlier during a "
4301 "previous stage)." );
4302 return( FALSE );
4303 }
4304 return( status );
4305 }
4306
testCMSEnvelopePKCCryptDoubleCert(void)4307 int testCMSEnvelopePKCCryptDoubleCert( void )
4308 {
4309 CRYPT_KEYSET cryptKeyset;
4310 int status;
4311
4312 /* The dual-certificate test uses cryptlib's internal key management to
4313 read the appropriate certificate from a database keyset, if this
4314 hasn't been set up then the test will fail so we try and detect the
4315 presence of the database keyset here. This isn't perfect since it
4316 requires that the database keyset be updated with the certificates in
4317 the same run as this test, but it's the best we can do */
4318 if( !doubleCertOK )
4319 {
4320 puts( "The certificate database wasn't updated with dual encryption/"
4321 "signing certs\nduring this test run (either because database "
4322 "keysets aren't enabled in this\nbuild of cryptlib or because "
4323 "only some portions of the self-tests are being\nrun), "
4324 "skipping the test of CMS enveloping with dual certs.\n" );
4325 return( TRUE );
4326 }
4327
4328 /* Since we're using certs with the same DN and email address present
4329 in multiple certs, we can't use the generic user keyset but have to
4330 use one that has been set up to have multiple certs that differ
4331 only in keyUsage */
4332 status = cryptKeysetOpen( &cryptKeyset, CRYPT_UNUSED, CRYPT_KEYSET_FILE,
4333 DUAL_PRIVKEY_FILE, CRYPT_KEYOPT_READONLY );
4334 if( cryptStatusError( status ) )
4335 {
4336 puts( "Couldn't find keyset with dual encryption/signature certs "
4337 "for test of dual certificate\nencryption." );
4338 return( FALSE );
4339 }
4340 status = cmsEnvelopeCrypt( "smi_pkcr", TRUE, FALSE, FALSE, FALSE,
4341 CRYPT_UNUSED, cryptKeyset,
4342 TEST_PRIVKEY_PASSWORD,
4343 TEXT( "dave@wetaburgers.com" ) );
4344 cryptKeysetClose( cryptKeyset );
4345 if( status == CRYPT_ERROR_NOTFOUND )
4346 { /* Datasize, recipient */
4347 puts( " (This is probably because the public key certificate was "
4348 "regenerated after\n the certificate stored with the "
4349 "private key was created, so that the\n private key can't "
4350 "be identified any more using the public key that was\n "
4351 "used for encryption. This can happen when the cryptlib "
4352 "self-test is run\n in separate stages, with one stage "
4353 "re-using data that was created\n earlier during a "
4354 "previous stage)." );
4355 return( FALSE );
4356 }
4357 return( status );
4358 }
4359
4360 /****************************************************************************
4361 * *
4362 * Test Data Import Routines *
4363 * *
4364 ****************************************************************************/
4365
4366 /* Import S/MIME signed data */
4367
testCMSEnvelopeSignedDataImport(void)4368 int testCMSEnvelopeSignedDataImport( void )
4369 {
4370 FILE *filePtr;
4371 BYTE fileName[ BUFFER_SIZE ];
4372 int i;
4373
4374 /* Make sure that the test data is present so that we can return a
4375 useful error message */
4376 filenameFromTemplate( fileName, SMIME_SIG_FILE_TEMPLATE, 1 );
4377 if( ( filePtr = fopen( fileName, "rb" ) ) == NULL )
4378 {
4379 puts( "Couldn't find S/MIME SignedData file, skipping test of "
4380 "SignedData import..." );
4381 return( TRUE );
4382 }
4383 fclose( filePtr );
4384
4385 /* There are many encoding variations possible for signed data so we try
4386 a representative sample to make sure that the code works in all
4387 cases */
4388 for( i = 1; i <= 3; i++ )
4389 {
4390 filenameFromTemplate( fileName, SMIME_SIG_FILE_TEMPLATE, i );
4391 if( !cmsImportSignedData( fileName, i ) && i != 2 )
4392 {
4393 /* AuthentiCode sig check fails for some reason */
4394 return( FALSE );
4395 }
4396 }
4397
4398 puts( "Import of S/MIME SignedData succeeded.\n" );
4399
4400 return( TRUE );
4401 }
4402
4403 /* Import S/MIME encrypted data */
4404
testCMSEnvelopePKCCryptImport(void)4405 int testCMSEnvelopePKCCryptImport( void )
4406 {
4407 FILE *filePtr;
4408 BYTE fileName[ BUFFER_SIZE ];
4409 int i;
4410
4411 /* Make sure that the test data is present so that we can return a
4412 useful error message */
4413 filenameFromTemplate( fileName, SMIME_ENV_FILE_TEMPLATE, 1 );
4414 if( ( filePtr = fopen( fileName, "rb" ) ) == NULL )
4415 {
4416 puts( "Couldn't find S/MIME EnvelopedData file, skipping test of "
4417 "EnvelopedData import..." );
4418 return( TRUE );
4419 }
4420 fclose( filePtr );
4421
4422 /* Enveloped data requires decryption keys that aren't generally
4423 available, so all that we do in this case is make sure that we can
4424 parse the data */
4425 for( i = 1; i <= 1; i++ )
4426 {
4427 filenameFromTemplate( fileName, SMIME_ENV_FILE_TEMPLATE, i );
4428 if( !cmsImportEnvelopedData( fileName, i ) )
4429 return( FALSE );
4430 }
4431
4432 puts( "Import of S/MIME EnvelopedData succeeded.\n" );
4433
4434 return( TRUE );
4435 }
4436
4437 /* Import CMS password-encrypted/authenticated data */
4438
testEnvelopePasswordCryptImport(void)4439 int testEnvelopePasswordCryptImport( void )
4440 {
4441 FILE *filePtr;
4442 BYTE fileName[ BUFFER_SIZE ];
4443 int i;
4444
4445 /* Make sure that the test data is present so that we can return a
4446 useful error message */
4447 filenameFromTemplate( fileName, CMS_ENC_FILE_TEMPLATE, 1 );
4448 if( ( filePtr = fopen( fileName, "rb" ) ) == NULL )
4449 {
4450 puts( "Couldn't find CMS EnvelopedData file, skipping test of "
4451 "EnvelopedData/AuthentcatedData import..." );
4452 return( TRUE );
4453 }
4454 fclose( filePtr );
4455
4456 /* Process the password-protected data. The files are:
4457
4458 File 1: CMS Authenticated data, AES-256 key wrap with HMAC-SHA1.
4459
4460 File 2: CMS Enveloped data, AES-128 key wrap with AES-128 */
4461 for( i = 1; i <= 2; i++ )
4462 {
4463 int count;
4464
4465 count = readFileFromTemplate( CMS_ENC_FILE_TEMPLATE, i,
4466 "CMS password-encrypted/authd data",
4467 globalBuffer, BUFFER_SIZE );
4468 if( count <= 0 )
4469 return( FALSE );
4470 if( !cmsEnvelopeDecrypt( globalBuffer, count, CRYPT_UNUSED,
4471 TEST_PASSWORD, FALSE ) )
4472 return( FALSE );
4473 }
4474
4475 puts( "Import of CMS password-encrypted/authenticated data "
4476 "succeeded.\n" );
4477
4478 return( TRUE );
4479 }
4480
4481 /* Import PGP 2.x and OpenPGP-generated password-encrypted data */
4482
testPGPEnvelopePasswordCryptImport(void)4483 int testPGPEnvelopePasswordCryptImport( void )
4484 {
4485 int count;
4486
4487 /* Process the PGP 2.x data: IDEA with MD5 hash. Create with:
4488
4489 pgp -c +compress=off -o conv_enc1.pgp test.txt */
4490 count = readFileFromTemplate( PGP_ENC_FILE_TEMPLATE, 1,
4491 "PGP password-encrypted data",
4492 globalBuffer, BUFFER_SIZE );
4493 if( count <= 0 )
4494 return( FALSE );
4495 count = envelopePasswordDecrypt( globalBuffer, count );
4496 if( count <= 0 )
4497 return( FALSE );
4498 if( !compareData( ENVELOPE_PGP_TESTDATA, ENVELOPE_TESTDATA_SIZE,
4499 globalBuffer, count ) )
4500 return( FALSE );
4501 puts( "Import of PGP password-encrypted data succeeded." );
4502
4503 /* Process the OpenPGP data, all with password "password". The files are:
4504
4505 File 2: 3DES with SHA1 hash. Create with:
4506
4507 pgp65 -c +compress=off -o conv_enc2.pgp test.txt
4508
4509 File 3: 3DES with SHA1 non-iterated hash. Create with:
4510
4511 gpg -c -z 0 --cipher-algo 3des --s2k-mode 1 -o conv_enc3.pgp test.txt
4512
4513 File 4: AES without MDC. Create with
4514
4515 gpg -c -z 0 --disable-mdc --cipher-algo aes -o conv_enc4.pgp test.txt
4516
4517 File 5: AES with MDC. Create with:
4518
4519 gpg -c -z 0 --cipher-algo aes -o conv_enc5.pgp test.txt
4520
4521 File 6: AES with MDC and indefinite inner length. Create with:
4522
4523 gpg -c --cipher-algo aes -o conv_enc5.pgp test.txt
4524
4525 File 7: 3DES with partial lengths. Create with:
4526
4527 cat test.c | gpg -c -z 0 --cipher-algo 3des -o conv_enc6.pgp
4528
4529 Note that this requires using a file with a minimum length of a
4530 few hundred bytes, since anything shorter is encoded into a
4531 fixed-length packet.
4532
4533 Since the inner content for files 6 and 7 are indefinite-length, we
4534 need to process that in a separate pass, which we do by handing it to
4535 the compressed-data de-enveloping code, this is really a general
4536 "process non-encrypted content" function so we get back the inner
4537 content */
4538 count = readFileFromTemplate( PGP_ENC_FILE_TEMPLATE, 2,
4539 "OpenPGP password-encrypted data (3DES)",
4540 globalBuffer, BUFFER_SIZE );
4541 if( count <= 0 )
4542 return( FALSE );
4543 if( !envelopePasswordDecrypt( globalBuffer, count ) )
4544 return( FALSE );
4545 if( !compareData( ENVELOPE_PGP_TESTDATA, ENVELOPE_TESTDATA_SIZE,
4546 globalBuffer, ENVELOPE_TESTDATA_SIZE ) )
4547 return( FALSE );
4548 count = readFileFromTemplate( PGP_ENC_FILE_TEMPLATE, 3,
4549 "OpenPGP password-encrypted data (3DES+non-iterated hash)",
4550 globalBuffer, BUFFER_SIZE );
4551 if( count <= 0 )
4552 return( FALSE );
4553 if( !envelopePasswordDecrypt( globalBuffer, count ) )
4554 return( FALSE );
4555 if( !compareData( ENVELOPE_PGP_TESTDATA, ENVELOPE_TESTDATA_SIZE,
4556 globalBuffer, ENVELOPE_TESTDATA_SIZE ) )
4557 return( FALSE );
4558 count = readFileFromTemplate( PGP_ENC_FILE_TEMPLATE, 4,
4559 "OpenPGP password-encrypted data (AES)",
4560 globalBuffer, BUFFER_SIZE );
4561 if( count <= 0 )
4562 return( FALSE );
4563 if( !envelopePasswordDecrypt( globalBuffer, count ) )
4564 return( FALSE );
4565 if( !compareData( ENVELOPE_PGP_TESTDATA, ENVELOPE_TESTDATA_SIZE,
4566 globalBuffer, ENVELOPE_TESTDATA_SIZE ) )
4567 return( FALSE );
4568 count = readFileFromTemplate( PGP_ENC_FILE_TEMPLATE, 5,
4569 "OpenPGP password-encrypted data (AES+MDC)",
4570 globalBuffer, BUFFER_SIZE );
4571 if( count <= 0 )
4572 return( FALSE );
4573 if( !envelopePasswordDecrypt( globalBuffer, count ) )
4574 return( FALSE );
4575 if( !compareData( ENVELOPE_PGP_TESTDATA, ENVELOPE_TESTDATA_SIZE,
4576 globalBuffer, ENVELOPE_TESTDATA_SIZE ) )
4577 return( FALSE );
4578 count = readFileFromTemplate( PGP_ENC_FILE_TEMPLATE, 6,
4579 "OpenPGP password-encrypted data (AES+MDC, indef-len inner)",
4580 globalBuffer, BUFFER_SIZE );
4581 if( count <= 0 )
4582 return( FALSE );
4583 count = envelopePasswordDecrypt( globalBuffer, count );
4584 if( count <= 0 )
4585 return( FALSE );
4586 count = envelopeDecompress( globalBuffer, BUFFER_SIZE, count );
4587 if( count <= 0 )
4588 return( FALSE );
4589 if( !compareData( ENVELOPE_PGP_TESTDATA, ENVELOPE_TESTDATA_SIZE,
4590 globalBuffer, ENVELOPE_TESTDATA_SIZE ) )
4591 return( FALSE );
4592 count = readFileFromTemplate( PGP_ENC_FILE_TEMPLATE, 7,
4593 "OpenPGP password-encrypted data (partial lengths)",
4594 globalBuffer, BUFFER_SIZE );
4595 if( count <= 0 )
4596 return( FALSE );
4597 count = envelopePasswordDecrypt( globalBuffer, count );
4598 if( count <= 0 )
4599 return( FALSE );
4600 count = envelopeDecompress( globalBuffer, BUFFER_SIZE, count );
4601 if( count <= 0 )
4602 return( FALSE );
4603 if( !compareData( ENVELOPE_COMPRESSEDDATA, ENVELOPE_TESTDATA_SIZE,
4604 globalBuffer, ENVELOPE_TESTDATA_SIZE ) )
4605 return( FALSE );
4606 puts( "Import of OpenPGP password-encrypted data succeeded.\n" );
4607
4608 return( TRUE );
4609 }
4610
4611 /* Import PGP 2.x and OpenPGP-generated PKC-encrypted data */
4612
testPGPEnvelopePKCCryptImport(void)4613 int testPGPEnvelopePKCCryptImport( void )
4614 {
4615 int count;
4616
4617 /* Process the PGP 2.x encrypted data */
4618 #ifdef USE_PGP2
4619 count = readFileFromTemplate( PGP_PKE_FILE_TEMPLATE, 1,
4620 "PGP-encrypted data", globalBuffer,
4621 BUFFER_SIZE );
4622 if( count <= 0 )
4623 return( FALSE );
4624 count = envelopePKCDecrypt( globalBuffer, count, KEYFILE_PGP,
4625 CRYPT_UNUSED );
4626 if( count <= 0 )
4627 return( FALSE );
4628 if( !compareData( ENVELOPE_PGP_TESTDATA, ENVELOPE_TESTDATA_SIZE,
4629 globalBuffer, count ) )
4630 return( FALSE );
4631 count = readFileFromTemplate( PGP_PKE_FILE_TEMPLATE, 2,
4632 "PGP (NAI)-encrypted data", globalBuffer,
4633 BUFFER_SIZE );
4634 if( count <= 0 )
4635 return( FALSE );
4636 count = envelopePKCDecrypt( globalBuffer, count, KEYFILE_NAIPGP,
4637 CRYPT_UNUSED );
4638 if( count <= 0 )
4639 return( FALSE );
4640 if( globalBuffer[ 0 ] != 0xA3 || globalBuffer[ 1 ] != 0x01 || \
4641 globalBuffer[ 2 ] != 0x5B || globalBuffer[ 3 ] != 0x53 )
4642 {
4643 puts( "De-enveloped data != original data." );
4644 return( FALSE );
4645 }
4646 puts( "Import of PGP-encrypted data succeeded." );
4647 #endif /* USE_PGP2 */
4648
4649 /* Process the OpenPGP encrypted data. The files are:
4650
4651 File 1: RSA with 3DES. Create with:
4652
4653 pgpo -e +pubring=".\pubring.pgp" +compress=off -o gpg_enc1.pgp -r test test.txt
4654
4655 (In theory it could be created with
4656 gpg -e -z 0 --homedir . --always-trust -r test test.txt
4657 and pubring.pgp renamed to pubring.gpg, however GPG won't allow
4658 the use of the RSA key in pubring.pgp no matter what command-
4659 line options you specify because it's not self-signed).
4660
4661 File 2: Elgamal and AES without MDC. Create with:
4662
4663 cp sec_hash.gpg secring.gpg
4664 cp pub_hash.gpg pubring.gpg
4665 gpg -e --disable-mdc -z 0 --homedir . -o gpg_enc2.gpg -r test1 test.txt
4666 rm secring.gpg pubring.gpg
4667
4668 File 3: Elgamal and AES with MDC. Create with:
4669
4670 cp sec_hash.gpg secring.gpg
4671 cp pub_hash.gpg pubring.gpg
4672 gpg -e -z 0 --homedir . -o gpg_enc3.gpg -r test1 test.txt
4673 rm secring.gpg pubring.gpg
4674
4675 File 4: Elgamal and Blowfish with MDC. Create with:
4676
4677 cp sec_hash.gpg secring.gpg
4678 cp pub_hash.gpg pubring.gpg
4679 gpg -e -z 0 --homedir . --cipher-algo blowfish -o gpg_enc4.gpg -r test1 test.txt
4680 rm secring.gpg pubring.gpg
4681
4682 File 5: Elgamal and AES with MDC and partial lengths (not sure how
4683 this was created) */
4684 #ifdef USE_PGP2 /* Uses PGP 2.x private keyring */
4685 count = readFileFromTemplate( OPENPGP_PKE_FILE_TEMPLATE, 1,
4686 "OpenPGP (GPG)-encrypted data",
4687 globalBuffer, BUFFER_SIZE );
4688 if( count <= 0 )
4689 return( FALSE );
4690 count = envelopePKCDecrypt( globalBuffer, count, KEYFILE_PGP,
4691 CRYPT_UNUSED );
4692 if( count <= 0 )
4693 return( FALSE );
4694 if( !compareData( ENVELOPE_PGP_TESTDATA, ENVELOPE_TESTDATA_SIZE,
4695 globalBuffer, count ) )
4696 return( FALSE );
4697 #endif /* USE_PGP2 */
4698 count = readFileFromTemplate( OPENPGP_PKE_FILE_TEMPLATE, 2,
4699 "OpenPGP (GPG)-encrypted data (AES)",
4700 globalBuffer, BUFFER_SIZE );
4701 if( count <= 0 )
4702 return( FALSE );
4703 count = envelopePKCDecrypt( globalBuffer, count, KEYFILE_OPENPGP_HASH,
4704 CRYPT_UNUSED );
4705 if( count <= 0 )
4706 return( FALSE );
4707 if( !compareData( ENVELOPE_PGP_TESTDATA, ENVELOPE_TESTDATA_SIZE,
4708 globalBuffer, count ) )
4709 return( FALSE );
4710 count = readFileFromTemplate( OPENPGP_PKE_FILE_TEMPLATE, 3,
4711 "OpenPGP (GPG)-encrypted data (AES+MDC)",
4712 globalBuffer, BUFFER_SIZE );
4713 if( count <= 0 )
4714 return( FALSE );
4715 count = envelopePKCDecrypt( globalBuffer, count, KEYFILE_OPENPGP_HASH,
4716 CRYPT_UNUSED );
4717 if( count <= 0 )
4718 return( FALSE );
4719 if( !compareData( ENVELOPE_PGP_TESTDATA, ENVELOPE_TESTDATA_SIZE,
4720 globalBuffer, count ) )
4721 return( FALSE );
4722 #ifdef USE_BLOWFISH /* Uses Blowfish for encryption */
4723 count = readFileFromTemplate( OPENPGP_PKE_FILE_TEMPLATE, 4,
4724 "OpenPGP (GPG)-encrypted data (Blowfish+MDC)",
4725 globalBuffer, BUFFER_SIZE );
4726 if( count <= 0 )
4727 return( FALSE );
4728 count = envelopePKCDecrypt( globalBuffer, count, KEYFILE_OPENPGP_HASH,
4729 CRYPT_UNUSED );
4730 if( count <= 0 )
4731 return( FALSE );
4732 if( !compareData( ENVELOPE_PGP_TESTDATA, ENVELOPE_TESTDATA_SIZE,
4733 globalBuffer, count ) )
4734 return( FALSE );
4735 #endif /* USE_BLOWFISH */
4736 count = readFileFromTemplate( OPENPGP_PKE_FILE_TEMPLATE, 5,
4737 "OpenPGP (GPG)-encrypted data (partial lengths)",
4738 globalBuffer, BUFFER_SIZE );
4739 if( count <= 0 )
4740 return( FALSE );
4741 count = envelopePKCDecrypt( globalBuffer, count, KEYFILE_OPENPGP_PARTIAL,
4742 CRYPT_UNUSED );
4743 if( count <= 0 )
4744 return( FALSE );
4745 count = envelopeDecompress( globalBuffer, BUFFER_SIZE, count );
4746 if( count <= 0 )
4747 return( FALSE );
4748 if( count < 600 || \
4749 !compareData( "\n\n<sect>Vorwort\n", 16, globalBuffer, 16 ) )
4750 return( FALSE );
4751 puts( "Import of OpenPGP-encrypted data succeeded.\n" );
4752
4753 return( TRUE );
4754 }
4755
4756 /* Import PGP 2.x and OpenPGP-generated signed data */
4757
testPGPEnvelopeSignedDataImport(void)4758 int testPGPEnvelopeSignedDataImport( void )
4759 {
4760 CRYPT_CONTEXT hashContext;
4761 int count, status;
4762
4763 /* Process the PGP 2.x signed data. Create with:
4764
4765 pgp -s +secring="secring.pgp" +pubring="pubring.pgp" -u test test.txt */
4766 #ifdef USE_PGP2
4767 count = readFileFromTemplate( PGP_SIG_FILE_TEMPLATE, 1,
4768 "PGP-signed data", globalBuffer,
4769 BUFFER_SIZE );
4770 if( count <= 0 )
4771 return( FALSE );
4772 count = envelopeSigCheck( globalBuffer, count, CRYPT_UNUSED,
4773 CRYPT_UNUSED, KEYFILE_PGP, FALSE,
4774 CRYPT_FORMAT_PGP );
4775 if( count <= 0 )
4776 return( FALSE );
4777 if( !compareData( ENVELOPE_PGP_TESTDATA, ENVELOPE_TESTDATA_SIZE,
4778 globalBuffer, count ) )
4779 return( FALSE );
4780 puts( "Import of PGP-signed data succeeded." );
4781 #endif /* USE_PGP2 */
4782
4783 #if 0 /* Disabled because it uses a 512-bit sig and there doesn't appear to
4784 be any way to create a new file in this format */
4785 /* Process the OpenPGP (actually a weird 2.x/OpenPGP hybrid produced by
4786 PGP 5.0) signed data. In theory this could be created with:
4787
4788 pgpo -s +secring="secring.pgp" +pubring="pubring.pgp" +compress=off -o signed2.pgp -u test test.txt
4789
4790 but the exact details of how to create this packet are a mystery, it
4791 starts with a marker packet and then a one-pass sig, which isn't
4792 generated by default by any of the PGP 5.x or 6.x versions */
4793 count = readFileFromTemplate( PGP_SIG_FILE_TEMPLATE, 2,
4794 "PGP 2.x/OpenPGP-hybrid-signed data",
4795 globalBuffer, BUFFER_SIZE );
4796 if( count <= 0 )
4797 return( FALSE );
4798 count = envelopeSigCheck( globalBuffer, count, CRYPT_UNUSED,
4799 CRYPT_UNUSED, TRUE, FALSE, FALSE,
4800 CRYPT_FORMAT_PGP );
4801 if( count <= 0 )
4802 return( FALSE );
4803 if( !compareData( ENVELOPE_PGP_TESTDATA, ENVELOPE_TESTDATA_SIZE,
4804 globalBuffer, count ) )
4805 return( FALSE );
4806 puts( "Import of PGP 2.x/OpenPGP-hybrid-signed data succeeded." );
4807 #endif /* 0 */
4808
4809 /* Process the OpenPGP signed data: DSA with SHA1. Create with:
4810
4811 cp sec_hash.gpg secring.gpg
4812 cp pub_hash.gpg pubring.gpg
4813 gpg -s -z 0 --homedir . -o signed3.pgp test.txt
4814 rm secring.gpg pubring.gpg */
4815 count = readFileFromTemplate( PGP_SIG_FILE_TEMPLATE, 3,
4816 "OpenPGP-signed data",
4817 globalBuffer, BUFFER_SIZE );
4818 if( count <= 0 )
4819 return( FALSE );
4820 count = envelopeSigCheck( globalBuffer, count, CRYPT_UNUSED,
4821 CRYPT_UNUSED, KEYFILE_OPENPGP_HASH, FALSE,
4822 CRYPT_FORMAT_PGP );
4823 if( count <= 0 )
4824 return( FALSE );
4825 if( !compareData( ENVELOPE_PGP_TESTDATA, ENVELOPE_TESTDATA_SIZE,
4826 globalBuffer, count ) )
4827 return( FALSE );
4828 puts( "Import of OpenPGP-signed data succeeded." );
4829
4830 /* Process the OpenPGP detached signed data. Create with:
4831
4832 cp sec_hash.gpg secring.gpg
4833 cp pub_hash.gpg pubring.gpg
4834 gpg -b -z 0 --openpgp --homedir . -o signed4.pgp test.txt
4835 rm secring.gpg pubring.gpg
4836
4837 (the --openpgp is for another GPG bug, without it it'll generate
4838 v3 sigs as if --force-v3-sigs had been specified). The data is
4839 provided externally so we have to hash it ourselves. Since PGP
4840 hashes further data after hashing the content, we can't complete
4841 the hashing but have to use the partially-completed hash */
4842 status = cryptCreateContext( &hashContext, CRYPT_UNUSED,
4843 CRYPT_ALGO_SHA1 );
4844 if( cryptStatusOK( status ) )
4845 status = cryptEncrypt( hashContext, ENVELOPE_PGP_TESTDATA,
4846 ENVELOPE_TESTDATA_SIZE );
4847 if( cryptStatusError( status ) )
4848 {
4849 puts( "Couldn't create external hash of data." );
4850 return( FALSE );
4851 }
4852 count = readFileFromTemplate( PGP_SIG_FILE_TEMPLATE, 4,
4853 "OpenPGP-signed data with externally-supplied hash",
4854 globalBuffer, BUFFER_SIZE );
4855 if( count <= 0 )
4856 return( FALSE );
4857 count = envelopeSigCheck( globalBuffer, count, hashContext,
4858 CRYPT_UNUSED, KEYFILE_OPENPGP_HASH, TRUE,
4859 CRYPT_FORMAT_PGP );
4860 cryptDestroyContext( hashContext );
4861 if( count <= 0 )
4862 return( FALSE );
4863 puts( "Import of OpenPGP-signed data with externally-supplied hash "
4864 "succeeded.\n" );
4865
4866 return( TRUE );
4867 }
4868
4869 /* Import PGP 2.x and OpenPGP-generated compressed data */
4870
testPGPEnvelopeCompressedDataImport(void)4871 int testPGPEnvelopeCompressedDataImport( void )
4872 {
4873 BYTE *bufPtr;
4874 int count;
4875
4876 /* Since this needs a nontrivial amount of data for the compression, we
4877 use a dynamically-allocated buffer */
4878 if( ( bufPtr = malloc( FILEBUFFER_SIZE ) ) == NULL )
4879 {
4880 puts( "Couldn't allocate test buffer." );
4881 return( FALSE );
4882 }
4883
4884 /* Process the PGP 2.x compressed data */
4885 count = readFileFromTemplate( PGP_COPR_FILE_TEMPLATE, 1,
4886 "PGP 2.x compressed data",
4887 bufPtr, FILEBUFFER_SIZE );
4888 if( count <= 0 )
4889 {
4890 free( bufPtr );
4891 return( FALSE );
4892 }
4893 count = envelopeDecompress( bufPtr, FILEBUFFER_SIZE, count );
4894 if( count <= 0 )
4895 {
4896 free( bufPtr );
4897 return( FALSE );
4898 }
4899 if( !compareData( bufPtr, ENVELOPE_COMPRESSEDDATA_SIZE,
4900 ENVELOPE_COMPRESSEDDATA, ENVELOPE_COMPRESSEDDATA_SIZE ) )
4901 {
4902 free( bufPtr );
4903 return( FALSE );
4904 }
4905 puts( "Import of PGP 2.x compressed data succeeded.\n" );
4906
4907 /* Process the OpenPGP compressed nested data. GPG is weird in that
4908 instead of signing compressed data it first creates the signature
4909 and then compresses that, so that the result isn't { one-pass sig,
4910 copr.data, signature } but { copr.data { one-pass sig, data,
4911 signature } }. Create with:
4912
4913 cp sec_hash.gpg secring.gpg
4914 cp pub_hash.gpg pubring.gpg
4915 gpg -s --openpgp --homedir . -o copr2.pgp test.c
4916 rm secring.gpg pubring.gpg
4917
4918 with the same note as before for GPG bugs and --openpgp */
4919 count = readFileFromTemplate( PGP_COPR_FILE_TEMPLATE, 2,
4920 "OpenPGP compressed signed data",
4921 bufPtr, FILEBUFFER_SIZE );
4922 if( count <= 0 )
4923 {
4924 free( bufPtr );
4925 return( FALSE );
4926 }
4927 count = envelopeDecompress( bufPtr, FILEBUFFER_SIZE, count );
4928 if( count <= 0 )
4929 {
4930 free( bufPtr );
4931 return( FALSE );
4932 }
4933 if( !compareData( "\x90\x0D\x03\x00", 4, bufPtr, 4 ) )
4934 {
4935 free( bufPtr );
4936 return( FALSE );
4937 }
4938 memcpy( globalBuffer, bufPtr, count );
4939 free( bufPtr );
4940 debugDump( "decopr_sig.pgp", globalBuffer, count );
4941 count = envelopeSigCheck( globalBuffer, count, CRYPT_UNUSED,
4942 CRYPT_UNUSED, KEYFILE_OPENPGP_HASH, FALSE,
4943 CRYPT_FORMAT_PGP );
4944 if( count <= 0 )
4945 return( FALSE );
4946 if( !compareData( ENVELOPE_COMPRESSEDDATA, ENVELOPE_COMPRESSEDDATA_SIZE,
4947 globalBuffer, ENVELOPE_COMPRESSEDDATA_SIZE ) )
4948 return( FALSE );
4949 puts( "Import of OpenPGP compressed signed data succeeded.\n" );
4950
4951 return( TRUE );
4952 }
4953
4954 /* Generic test routines used for debugging. These are only meant to be
4955 used interactively, and throw exceptions rather than returning status
4956 values */
4957
dataImport(void * buffer,const int length,const BOOLEAN resultBad)4958 static void dataImport( void *buffer, const int length,
4959 const BOOLEAN resultBad )
4960 {
4961 CRYPT_ENVELOPE cryptEnvelope;
4962 int count, status;
4963
4964 status = createDeenvelope( &cryptEnvelope );
4965 assert( status == TRUE );
4966 count = pushData( cryptEnvelope, buffer, length, NULL, 0 );
4967 if( resultBad )
4968 {
4969 assert( cryptStatusError( count ) );
4970 return;
4971 }
4972 assert( !cryptStatusError( count ) );
4973 count = popData( cryptEnvelope, buffer, length );
4974 assert( !cryptStatusError( count ) );
4975 status = destroyEnvelope( cryptEnvelope );
4976 assert( status == TRUE );
4977 }
4978
xxxDataImport(const char * fileName)4979 void xxxDataImport( const char *fileName )
4980 {
4981 BYTE *bufPtr = globalBuffer;
4982 int count;
4983
4984 count = getFileSize( fileName ) + 10;
4985 if( count >= BUFFER_SIZE && \
4986 ( bufPtr = malloc( count ) ) == NULL )
4987 {
4988 assert( 0 );
4989 return;
4990 }
4991 count = readFileData( fileName, "Generic test data", bufPtr, count, 32,
4992 FALSE );
4993 assert( count > 0 );
4994 dataImport( bufPtr, count, FALSE );
4995 if( bufPtr != globalBuffer )
4996 free( bufPtr );
4997 }
4998
xxxSignedDataImport(const char * fileName)4999 void xxxSignedDataImport( const char *fileName )
5000 {
5001 BYTE *bufPtr = globalBuffer;
5002 int count, status;
5003
5004 count = getFileSize( fileName ) + 10;
5005 if( count >= BUFFER_SIZE && \
5006 ( bufPtr = malloc( count ) ) == NULL )
5007 {
5008 assert( 0 );
5009 return;
5010 }
5011 count = readFileData( fileName, "S/MIME test data", bufPtr, count, 64,
5012 FALSE );
5013 assert( count > 0 );
5014 status = cmsEnvelopeSigCheck( bufPtr, count, CRYPT_UNUSED, CRYPT_UNUSED,
5015 FALSE, FALSE, FALSE, FALSE, FALSE, FALSE );
5016 assert( status > 0 );
5017 if( bufPtr != globalBuffer )
5018 free( bufPtr );
5019 }
5020
xxxEncryptedDataImport(const char * fileName,const char * keyset,const char * password)5021 void xxxEncryptedDataImport( const char *fileName, const char *keyset,
5022 const char *password )
5023 {
5024 CRYPT_KEYSET cryptKeyset;
5025 BYTE *buffer = globalBuffer;
5026 int count, status;
5027
5028 count = getFileSize( fileName ) + 10;
5029 if( count >= BUFFER_SIZE )
5030 {
5031 buffer = malloc( count );
5032 assert( buffer != NULL );
5033 }
5034 count = readFileData( fileName, "S/MIME test data", buffer, 32,
5035 count, FALSE );
5036 assert( count > 0 );
5037 status = cryptKeysetOpen( &cryptKeyset, CRYPT_UNUSED, CRYPT_KEYSET_FILE,
5038 keyset, CRYPT_KEYOPT_READONLY );
5039 assert( cryptStatusOK( status ) );
5040 status = cmsEnvelopeDecrypt( buffer, count, cryptKeyset, password, FALSE );
5041 assert( status > 0 );
5042 cryptKeysetClose( cryptKeyset );
5043 if( buffer != globalBuffer )
5044 free( buffer );
5045 }
5046
xxxEnvelopeTest(void)5047 void xxxEnvelopeTest( void )
5048 {
5049 CRYPT_CERTIFICATE cryptCert;
5050
5051 importCertFile( &cryptCert, TEXT( "r:/cert.der" ) );
5052
5053 envelopePKCCrypt( "r:/test.p7m", TRUE, KEYFILE_NONE, FALSE,
5054 FALSE, FALSE, TRUE, CRYPT_FORMAT_CMS, cryptCert, 0 );
5055 }
5056 #endif /* TEST_ENVELOPE || TEST_SESSION */
5057