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