1 /****************************************************************************
2 *																			*
3 *						cryptlib File Keyset Test Routines					*
4 *						Copyright Peter Gutmann 1995-2009					*
5 *																			*
6 ****************************************************************************/
7 
8 #include "cryptlib.h"
9 #include "test/test.h"
10 
11 #if defined( __MVS__ ) || defined( __VMCMS__ )
12   /* Suspend conversion of literals to ASCII. */
13   #pragma convlit( suspend )
14 #endif /* IBM big iron */
15 #if defined( __ILEC400__ )
16   #pragma convert( 0 )
17 #endif /* IBM medium iron */
18 #include "misc/config.h"
19 
20 /* External flags that indicate that the key read/update routines worked OK.
21    This is set by earlier self-test code, if it isn't set some of the tests
22    are disabled */
23 
24 extern int keyReadOK, doubleCertOK;
25 
26 #ifdef TEST_KEYSET
27 
28 /****************************************************************************
29 *																			*
30 *								Utility Routines							*
31 *																			*
32 ****************************************************************************/
33 
34 /* Get an algorithm name and the label for the key for that algorithm */
35 
getAlgoName(const CRYPT_ALGO_TYPE cryptAlgo)36 static const char *getAlgoName( const CRYPT_ALGO_TYPE cryptAlgo )
37 	{
38 	switch( cryptAlgo )
39 		{
40 		case CRYPT_ALGO_RSA:
41 			return( "RSA" );
42 
43 		case CRYPT_ALGO_DSA:
44 			return( "DSA" );
45 
46 		case CRYPT_ALGO_ELGAMAL:
47 			return( "Elgamal" );
48 
49 		case CRYPT_ALGO_ECDH:
50 			return( "ECDH" );
51 
52 		case CRYPT_ALGO_ECDSA:
53 			return( "ECDSA" );
54 		}
55 
56 	return( "<Unknown>" );
57 	}
58 
getAlgoLabel(const CRYPT_ALGO_TYPE cryptAlgo)59 static const C_STR getAlgoLabel( const CRYPT_ALGO_TYPE cryptAlgo )
60 	{
61 	switch( cryptAlgo )
62 		{
63 		case CRYPT_ALGO_RSA:
64 			return( RSA_PRIVKEY_LABEL );
65 
66 		case CRYPT_ALGO_DSA:
67 			return( DSA_PRIVKEY_LABEL );
68 
69 		case CRYPT_ALGO_ELGAMAL:
70 			return( ELGAMAL_PRIVKEY_LABEL );
71 
72 		case CRYPT_ALGO_ECDH:
73 			return( ECDSA_PRIVKEY_LABEL );
74 
75 		case CRYPT_ALGO_ECDSA:
76 			return( ECDSA_PRIVKEY_LABEL );
77 		}
78 
79 	return( TEXT( "<Unknown>" ) );
80 	}
81 
82 /* Load a private-key context for a particular algorithm */
83 
loadPrivateKeyContext(CRYPT_CONTEXT * cryptContext,const CRYPT_ALGO_TYPE cryptAlgo)84 static int loadPrivateKeyContext( CRYPT_CONTEXT *cryptContext,
85 								  const CRYPT_ALGO_TYPE cryptAlgo )
86 	{
87 	switch( cryptAlgo )
88 		{
89 		case CRYPT_ALGO_RSA:
90 			return( loadRSAContexts( CRYPT_UNUSED, NULL, cryptContext ) );
91 
92 		case CRYPT_ALGO_DSA:
93 			return( loadDSAContexts( CRYPT_UNUSED, NULL, cryptContext ) );
94 
95 		case CRYPT_ALGO_ELGAMAL:
96 			return( loadElgamalContexts( NULL, cryptContext ) );
97 
98 		case CRYPT_ALGO_ECDSA:
99 			return( loadECDSAContexts( CRYPT_UNUSED, NULL, cryptContext ) );
100 		}
101 
102 	printf( "Algorithm %d not available, line %d.\n", cryptAlgo, __LINE__ );
103 	return( FALSE );
104 	}
105 
106 /* Make sure that an item read from a keyset is a certificate */
107 
checkCertPresence(const CRYPT_HANDLE cryptHandle,const char * certTypeName,const CRYPT_CERTTYPE_TYPE certType)108 static int checkCertPresence( const CRYPT_HANDLE cryptHandle,
109 							  const char *certTypeName,
110 							  const CRYPT_CERTTYPE_TYPE certType )
111 	{
112 	int value, status;
113 
114 	/* Make sure that what we've got is a certificate */
115 	status = cryptGetAttribute( cryptHandle, CRYPT_CERTINFO_CERTTYPE,
116 								&value );
117 	if( cryptStatusError( status ) || value != certType )
118 		{
119 		printf( "Returned object isn't a %s, line %d.\n", certTypeName,
120 				__LINE__ );
121 		return( FALSE );
122 		}
123 
124 	/* The test that follows requires an encryption-capable algorithm, if
125 	   the algorithm can't be used for encryption then we skip it */
126 	status = cryptGetAttribute( cryptHandle, CRYPT_CTXINFO_ALGO, &value );
127 	if( cryptStatusError( status ) )
128 		{
129 		printf( "Couldn't read algorithm from certificate, line %d.\n",
130 				__LINE__ );
131 		return( FALSE );
132 		}
133 	if( value != CRYPT_ALGO_RSA )
134 		{
135 		puts( "(Skipping certificate use test since algorithm can't be used "
136 			  "for encryption)." );
137 		return( TRUE );
138 		}
139 
140 	/* Make sure that we can't use the read key (the certificate constrains
141 	   it from being used externally) */
142 	status = testCrypt( cryptHandle, cryptHandle, value, NULL, FALSE, TRUE );
143 	if( status != CRYPT_ERROR_NOTAVAIL && status != CRYPT_ERROR_PERMISSION )
144 		{
145 		puts( "Attempt to perform external operation on context with "
146 			  "internal-only action\npermissions succeeded. " );
147 		return( FALSE );
148 		}
149 
150 	return( TRUE );
151 	}
152 
153 /* Copy a source file to a destination file, corrupting a given byte in the
154    process.  This is used to test the ability of the keyset-processing code
155    to detect data manipulation in keyset data */
156 
copyModifiedFile(const C_STR srcFileName,const C_STR destFileName,const int bytePos)157 static int copyModifiedFile( const C_STR srcFileName,
158 							 const C_STR destFileName, const int bytePos )
159 	{
160 	FILE *filePtr;
161 	BYTE buffer[ BUFFER_SIZE ];
162 	int count = 0;
163 
164 	/* Read the source file into the data buffer */
165 	if( ( filePtr = fopen( convertFileName( srcFileName ), "rb" ) ) != NULL )
166 		{
167 		count = fread( buffer, 1, BUFFER_SIZE, filePtr );
168 		if( count >= BUFFER_SIZE )
169 			count = 0;
170 		fclose( filePtr );
171 		}
172 	if( count <= 0 )
173 		return( FALSE );
174 
175 	/* Corrupt a specific byte in the file */
176 	buffer[ bytePos ] ^= 0xFF;
177 
178 	/* Write the changed result to the output buffer */
179 	if( ( filePtr = fopen( convertFileName( destFileName ), "wb" ) ) != NULL )
180 		{
181 		int writeCount;
182 
183 		writeCount = fwrite( buffer, 1, count, filePtr );
184 		if( writeCount != count )
185 			count = 0;
186 		fclose( filePtr );
187 		}
188 
189 	return( ( count > 0 ) ? TRUE : FALSE );
190 	}
191 
192 /****************************************************************************
193 *																			*
194 *						PGP/PKCS #12 Key Read/Write Tests					*
195 *																			*
196 ****************************************************************************/
197 
198 /* Get a public key from a PGP keyring */
199 
getPGPPublicKey(const KEYFILE_TYPE keyFileType,const C_STR keyFileTemplate,const char * description)200 static int getPGPPublicKey( const KEYFILE_TYPE keyFileType,
201 							const C_STR keyFileTemplate,
202 							const char *description )
203 	{
204 	CRYPT_KEYSET cryptKeyset;
205 	CRYPT_CONTEXT cryptContext;
206 	FILE *filePtr;
207 	char fileName[ BUFFER_SIZE ];
208 #ifdef UNICODE_STRINGS
209 	wchar_t wcBuffer[ FILENAME_BUFFER_SIZE ];
210 #endif /* UNICODE_STRINGS */
211 	const C_STR keysetName = getKeyfileName( keyFileType, FALSE );
212 	int status;
213 
214 	/* If this is the first file read, check that the file actually exists
215 	   so that we can return an appropriate error message */
216 	if( keyFileType == KEYFILE_PGP )
217 		{
218 		if( ( filePtr = fopen( convertFileName( keysetName ),
219 							   "rb" ) ) == NULL )
220 			return( CRYPT_ERROR_FAILED );
221 		fclose( filePtr );
222 		keyReadOK = FALSE;
223 		}
224 
225 	/* If the caller has overridden the keyfile to use, use the caller-
226 	   supplied name */
227 	if( keyFileTemplate != NULL )
228 		{
229 		filenameFromTemplate( fileName, keyFileTemplate, 1 );
230 #ifdef UNICODE_STRINGS
231 		mbstowcs( wcBuffer, fileName, strlen( fileName ) + 1 );
232 		keysetName = wcBuffer;
233 #else
234 		keysetName = fileName;
235 #endif /* UNICODE_STRINGS */
236 		}
237 
238 	printf( "Testing %s public key read...\n", description );
239 
240 	/* Open the keyset */
241 	status = cryptKeysetOpen( &cryptKeyset, CRYPT_UNUSED, CRYPT_KEYSET_FILE,
242 							  keysetName, CRYPT_KEYOPT_READONLY );
243 	if( cryptStatusError( status ) )
244 		{
245 		printf( "cryptKeysetOpen() failed with error code %d, line %d.\n",
246 				status, __LINE__ );
247 		return( FALSE );
248 		}
249 
250 	/* Get the key.  The read of the special-case PGP keyring tests the
251 	   ability to handle over-long key packet groups so this should return
252 	   a not-found error due to the packets being skipped */
253 	status = cryptGetPublicKey( cryptKeyset, &cryptContext, CRYPT_KEYID_NAME,
254 								getKeyfileUserID( keyFileType, FALSE ) );
255 	if( ( keyFileType == KEYFILE_PGP_SPECIAL && \
256 		  status != CRYPT_ERROR_NOTFOUND ) || \
257 		( keyFileType != KEYFILE_PGP_SPECIAL && \
258 		  cryptStatusError( status ) ) )
259 		{
260 		printExtError( cryptKeyset, "cryptGetPublicKey()", status,
261 					   __LINE__ );
262 		return( FALSE );
263 		}
264 	cryptDestroyContext( cryptContext );
265 
266 	/* Close the keyset */
267 	status = cryptKeysetClose( cryptKeyset );
268 	if( cryptStatusError( status ) )
269 		{
270 		printf( "cryptKeysetClose() failed with error code %d, line %d.\n",
271 				status, __LINE__ );
272 		return( FALSE );
273 		}
274 
275 	printf( "Read of public key from %s keyring succeeded.\n\n",
276 			description );
277 	return( TRUE );
278 	}
279 
testGetPGPPublicKey(void)280 int testGetPGPPublicKey( void )
281 	{
282 	/* See testGetPGPPrivateKey() for the descriptions of the files */
283 	if( !getPGPPublicKey( KEYFILE_PGP, NULL, "PGP" ) )
284 		return( FALSE );
285 	if( !getPGPPublicKey( KEYFILE_OPENPGP_HASH, NULL, "OpenPGP (GPG/hashed key)" ) )
286 		return( FALSE );
287 	if( !getPGPPublicKey( KEYFILE_OPENPGP_AES, NULL, "OpenPGP (GPG/AES-256 key)" ) )
288 		return( FALSE );
289 #if 0	/* The key in this file has an S2K iteration count of 3.5M and will
290 		   be rejected by cryptlib's anti-DoS sanity checks */
291 	if( !getPGPPublicKey( KEYFILE_OPENPGP_CAST, NULL, "OpenPGP (GPG/CAST5 key)" ) )
292 		return( FALSE );
293 #endif /* 0 */
294 	if( !getPGPPublicKey( KEYFILE_OPENPGP_RSA, NULL, "OpenPGP (GPG/RSA key)" ) )
295 		return( FALSE );
296 	if( !getPGPPublicKey( KEYFILE_OPENPGP_MULT, NULL, "OpenPGP (multiple subkeys)" ) )
297 		return( FALSE );
298 	if( !getPGPPublicKey( KEYFILE_NAIPGP, NULL, "OpenPGP (NAI)" ) )
299 		return( FALSE );
300 #if 0	/* This file is nearly 100K long and consists of endless strings of
301 		   userIDs and signatures for the same identity, so it's rejected by
302 		   cryptlib's sanity-check code */
303 	if( !getPGPPublicKey( KEYFILE_PGP_SPECIAL, PGPKEY_FILE_TEMPLATE, "Complex PGP key" ) )
304 		return( FALSE );
305 #endif /* 0 */
306 #if 0	/* Not fully supported yet */
307 	if( !getPGPPublicKey( KEYFILE_OPENPGP_ECC, NULL, "OpenPGP (ECC)" ) )
308 		return( FALSE );
309 #endif /* 0 */
310 	return( TRUE );
311 	}
312 
313 /* Get a private key from a PGP keyring */
314 
getPGPPrivateKey(const KEYFILE_TYPE keyFileType,const char * description)315 static int getPGPPrivateKey( const KEYFILE_TYPE keyFileType,
316 							 const char *description )
317 	{
318 	CRYPT_KEYSET cryptKeyset;
319 	CRYPT_CONTEXT cryptContext;
320 	const C_STR keysetName = getKeyfileName( keyFileType, TRUE );
321 	const C_STR password = getKeyfilePassword( keyFileType );
322 	int status;
323 
324 	printf( "Testing %s private key read...\n", description );
325 
326 	/* Open the keyset */
327 	status = cryptKeysetOpen( &cryptKeyset, CRYPT_UNUSED, CRYPT_KEYSET_FILE,
328 							  keysetName, CRYPT_KEYOPT_READONLY );
329 	if( cryptStatusError( status ) )
330 		{
331 		printf( "cryptKeysetOpen() failed with error code %d, line %d.\n",
332 				status, __LINE__ );
333 		return( FALSE );
334 		}
335 
336 	/* Get the key.  First we try it without a password, if that fails we
337 	   retry it with the password - this tests a lot of the private-key get
338 	   functionality including things like key cacheing */
339 	status = cryptGetPrivateKey( cryptKeyset, &cryptContext, CRYPT_KEYID_NAME,
340  								 getKeyfileUserID( keyFileType, TRUE ), NULL );
341 	if( status == CRYPT_ERROR_WRONGKEY )
342 		{
343 		/* We need a password for this private key, get it from the user and
344 		   get the key again */
345 		status = cryptGetPrivateKey( cryptKeyset, &cryptContext,
346 									 CRYPT_KEYID_NAME,
347 									 getKeyfileUserID( keyFileType, TRUE ),
348 									 password );
349 		}
350 	if( cryptStatusError( status ) )
351 		{
352 		printExtError( cryptKeyset, "cryptGetPrivateKey()", status,
353 					   __LINE__ );
354 		return( FALSE );
355 		}
356 
357 	/* Make sure that we can use the key that we've read.  We can only do this
358 	   with PGP 2.x keys, OpenPGP's peculiar multi-keys identify two (or more)
359 	   keys with the same label and we can't specify (at this level) which
360 	   key we want to use (the enveloping code can be more specific and so
361 	   doesn't run into this problem) */
362 	if( keyFileType == KEYFILE_PGP )
363 		{
364 		int value;
365 
366 		status = cryptGetAttribute( cryptContext, CRYPT_CTXINFO_ALGO,
367 									&value );
368 		if( cryptStatusOK( status ) )
369 			{
370 			status = testCrypt( cryptContext, cryptContext, value, NULL,
371 								FALSE, FALSE );
372 			}
373 		if( cryptStatusError( status ) )
374 			return( FALSE );
375 		}
376 	cryptDestroyContext( cryptContext );
377 
378 	/* Close the keyset */
379 	status = cryptKeysetClose( cryptKeyset );
380 	if( cryptStatusError( status ) )
381 		{
382 		printf( "cryptKeysetClose() failed with error code %d, line %d.\n",
383 				status, __LINE__ );
384 		return( FALSE );
385 		}
386 
387 	/* The public and private key reads worked, remember this for later when
388 	   we use the keys in other tests */
389 	keyReadOK = TRUE;
390 
391 	printf( "Read of private key from %s keyring succeeded.\n\n",
392 			description );
393 	return( TRUE );
394 	}
395 
testGetPGPPrivateKey(void)396 int testGetPGPPrivateKey( void )
397 	{
398 	/* PGP 2.x file, RSA with IDEA, secring.pgp */
399 #ifdef USE_PGP2
400 	if( !getPGPPrivateKey( KEYFILE_PGP, "PGP" ) )
401 		return( FALSE );
402 #endif /* USE_PGP2 */
403 
404 	/* OpenPGP file, DSA+Elgamal with 3DES, sec_hash.gpg.  Create with:
405 
406 		gpg --gen-key --homedir . --s2k-cipher-algo 3des
407 
408 	   Select DSA+Elgamal, size 1024 bits, key does not expire,
409 	   name = Test1, email = test1@test.org, comment blank,
410 	   password = test1 */
411 	if( !getPGPPrivateKey( KEYFILE_OPENPGP_HASH, "OpenPGP (GPG/hashed key)" ) )
412 		return( FALSE );
413 
414 	/* OpenPGP file, DSA+Elgamal with AES, sec_aes.skr */
415 	if( !getPGPPrivateKey( KEYFILE_OPENPGP_AES, "OpenPGP (GPG/AES-256 key)" ) )
416 		return( FALSE );
417 
418 #if 0	/* The key in this file has an S2K iteration count of 3.5M and will
419 		   be rejected by cryptlib's anti-DoS sanity checks */
420 	/* OpenPGP file, DSA+Elgamal with CAST5, sec_cast.gpg */
421 	if( !getPGPPrivateKey( KEYFILE_OPENPGP_CAST, "OpenPGP (GPG/CAST5 key)" ) )
422 		return( FALSE );
423 #endif /* 0 */
424 
425 	/* OpenPGP file, RSA+RSA with 3DES and SHA256, sec_rsa.gpg.  Create with:
426 
427 		gpg --gen-key --homedir . --s2k-cipher-algo 3des --s2k-digest-algo sha256
428 
429 	   Select RSA, size 2048 bits, key does not expire, name = Test1,
430 	   email = test1@test.org, comment blank, password = test1 */
431 	if( !getPGPPrivateKey( KEYFILE_OPENPGP_RSA, "OpenPGP (GPG/RSA key)" ) )
432 		return( FALSE );
433 
434 	/* OpenPGP file, RSA with IDEA, sec_nai.skr */
435 #ifdef USE_PGP2
436 	if( !getPGPPrivateKey( KEYFILE_NAIPGP, "OpenPGP (NAI)" ) )
437 		return( FALSE );
438 #endif /* USE_PGP2 */
439 
440 	/* OpenPGP, RSA p and q swapped, sec_bc.gpg.  Create using
441 	   BouncyCastle */
442 	if( !getPGPPrivateKey( KEYFILE_OPENPGP_BOUNCYCASTLE, "OpenPGP (RSA p,q swapped)" ) )
443 		return( FALSE );
444 
445 	/* OpenPGP, ECC keys, sec_ecc.gpg.  Create using a development release
446 	   of GPG 2.x (which involves installing about a dozen dependency
447 	   libraries and apps), then:
448 
449 		gpg2 --expert --full-gen-key
450 
451 	   Select ECC, NIST P256, key does not expire, name = Test1,
452 	   email = test1@test.org, comment blank, password = test1 */
453 #if 0	/* Not fully supported yet */
454 	if( !getPGPPrivateKey( KEYFILE_OPENPGP_ECC, "OpenPGP (ECC)" ) )
455 		return( FALSE );
456 #endif /* 0 */
457 
458 	return( TRUE );
459 	}
460 
461 /* Get a key from a PKCS #12 file.  Because of the security problems
462    associated with this format, the code only checks the data format but
463    doesn't try to read or use the keys.  If anyone wants this, they'll
464    have to add the code themselves.  Your security warranty is automatically
465    void when you implement this */
466 
borkenKeyImport(const int fileNo)467 static int borkenKeyImport( const int fileNo )
468 	{
469 	CRYPT_KEYSET cryptKeyset;
470 	CRYPT_CONTEXT cryptContext;
471 	const C_STR userID;
472 	const C_STR password;
473 	BYTE buffer[ BUFFER_SIZE ];
474 	int status;
475 
476 	/* Set up the file access information:
477 
478 		Keyset #1 = CryptoAPI via OpenSSL, privKey with ID data and 3DES,
479 			then anonymous cert with RC2/40.
480 		Keyset #2 = CryptoAPI, privKey with ID data and 3DES, then
481 			anonymous cert with RC2/40.  The private key is identified via a
482 			GUID which we can't do much with so we pass in the special-case
483 			userID "[none]" meaning "return the first key that we find".
484 		Keyset #3 = Unknown source, cert chain in plaintext with ID data,
485 			then privKey with ID data and 3DES.  The userID for the private
486 			key is the single hex byte 0x8C, again we use "[none]" for this.
487 		Keyset #4 = OpenSSL, anonymous cert with RC2/40, then privKey with
488 			ID data and 3DES.
489 		Keyset #5 = Unknown source (possibly OpenSSL), anonymous cert with
490 			RC2/40, then privKey with ID data and 3DES.  Unlike keyset #4
491 			the ID data doesn't include a userID, so we again have to resort
492 			to "[none]" to read it.
493 		Keyset #6 = Unknown source, from some CA that generates the private
494 			key for you rather than allowing you to generate it.  Contains
495 			mostly indefinite-length encodings of data, currently not
496 			readable, see the comments in keyset/pkcs12_rd.c for more
497 			details.
498 		Keyset #7 = Nexus 4 phone, DSA cert and private key.
499 		Keyset #8 = EJBCA, ECDSA cert and private key in no documented format
500 			(the code reads it from reverse-engineering the DER dump).
501 		Keyset #9 = Windows, ECDSA cert and private key, as above, created
502 			by importing and exporting Keyset #8 to/from Windows */
503 	switch( fileNo )
504 		{
505 		case 1:
506 			userID = TEXT( "test pkcs#12" );
507 			password = TEXT( "test" );
508 			break;
509 
510 		case 2:
511 			userID = TEXT( "[none]" );		/* Label = GUID */
512 			password = TEXT( "<unknown>" );	/* Unknown, RC2=2C 28 14 C4 01 */
513 			break;
514 
515 		case 3:
516 			userID = TEXT( "[none]" );		/* No label, ID = 0x8C */
517 			password = TEXT( "7OPWKMIX" );
518 			break;
519 
520 		case 4:
521 			userID = TEXT( "server" );
522 			password = TEXT( "cryptlib" );
523 			break;
524 
525 		case 5:
526 			userID = TEXT( "[none]" );		/* No label, ID = hash */
527 			password = TEXT( "password" );
528 			break;
529 
530 		case 6:
531 			userID = TEXT( "SignLabel" );
532 			password = TEXT( "vpsign" );
533 
534 			/* See comment above */
535 			return( TRUE );
536 
537 		case 7:
538 			userID = TEXT( "ClientDSA" );
539 			password = TEXT( "nexus4" );
540 			break;
541 
542 		case 8:
543 			userID = TEXT( "CMG" );
544 			password = TEXT( "skylight" );
545 			break;
546 
547 		case 9:
548 			userID = TEXT( "[none]" );		/* Label = GUID */
549 			password = TEXT( "test" );
550 			break;
551 
552 		default:
553 			assert( 0 );
554 			return( FALSE );
555 		}
556 
557 	/* Open the file keyset.  Note that we print the usual test message only
558 	   after we try and open the keyset, in order to avoid a cascade of PKCS
559 	   #12 file non-opened messages */
560 	filenameFromTemplate( buffer, PKCS12_FILE_TEMPLATE, fileNo );
561 	status = cryptKeysetOpen( &cryptKeyset, CRYPT_UNUSED, CRYPT_KEYSET_FILE,
562 							  buffer, CRYPT_KEYOPT_READONLY );
563 	if( cryptStatusError( status ) && status == CRYPT_ERROR_NOTAVAIL )
564 		{
565 		/* If support for this isn't enabled, just exit quietly */
566 		return( TRUE );
567 		}
568 	printf( "Testing PKCS #12 file #%d import...\n", fileNo );
569 	if( cryptStatusError( status ) )
570 		{
571 		printf( "cryptKeysetOpen() failed with error code %d, line %d.\n",
572 				status, __LINE__ );
573 		return( FALSE );
574 		}
575 
576 	/* Get the key */
577 	status = cryptGetPrivateKey( cryptKeyset, &cryptContext, CRYPT_KEYID_NAME,
578  								 userID, password );
579 	if( cryptStatusError( status ) )
580 		{
581 		switch( fileNo )
582 			{
583 			case 1:
584 				/* This file has a 512-bit key and will give a
585 				   CRYPT_ERROR_NOSECURE on import */
586 				if( status == CRYPT_ERROR_NOSECURE )
587 					status = CRYPT_OK;
588 				break;
589 
590 			case  2:
591 				/* This file has an unknown password, although the cracked
592 				   RC2/40 key for it is 2C 28 14 C4 01 */
593 				if( status == CRYPT_ERROR_WRONGKEY )
594 					status = CRYPT_OK;
595 				break;
596 
597 			case 3:
598 				/* This file contains an invalid private key, specifically
599 				   ( q * u ) mod p != 1 (!!!) */
600 				if( status == CRYPT_ERROR_INVALID )
601 					status = CRYPT_OK;
602 				break;
603 			}
604 		if( cryptStatusError( status ) )
605 			{
606 			printExtError( cryptKeyset, "cryptGetPrivateKey()", status,
607 						   __LINE__ );
608 			return( FALSE );
609 			}
610 		}
611 	else
612 		{
613 		/* Make sure that we got a certificate alongside the private key */
614 		if( !checkCertPresence( cryptContext, "private key with certificate",
615 								CRYPT_CERTTYPE_CERTIFICATE ) )
616 			return( FALSE );
617 		cryptDestroyContext( cryptContext );
618 		}
619 
620 	/* Close the keyset */
621 	status = cryptKeysetClose( cryptKeyset );
622 	if( cryptStatusError( status ) )
623 		{
624 		printf( "cryptKeysetClose() failed with error code %d, line %d.\n",
625 				status, __LINE__ );
626 		return( FALSE );
627 		}
628 
629 	printf( "Read of key from PKCS #12 file #%d succeeded.\n\n", fileNo );
630 	return( TRUE );
631 	}
632 
testReadAltFileKey(void)633 int testReadAltFileKey( void )
634 	{
635 	int i;
636 
637 	for( i = 1; i <= 9; i++ )
638 		{
639 		if( !borkenKeyImport( i ) )
640 			return( FALSE );
641 		}
642 
643 	return( TRUE );
644 	}
645 
646 /****************************************************************************
647 *																			*
648 *						Public/Private Key Read/Write Tests					*
649 *																			*
650 ****************************************************************************/
651 
652 /* Read/write a private key from a file */
653 
readFileKey(const CRYPT_ALGO_TYPE cryptAlgo,const CRYPT_FORMAT_TYPE formatType,const BOOLEAN useWildcardRead)654 static int readFileKey( const CRYPT_ALGO_TYPE cryptAlgo,
655 						const CRYPT_FORMAT_TYPE formatType,
656 						const BOOLEAN useWildcardRead )
657 	{
658 	CRYPT_KEYSET cryptKeyset;
659 	CRYPT_CONTEXT cryptContext;
660 	const char *keyFileDescr = \
661 			( formatType == CRYPT_FORMAT_NONE ) ? "alternative " : \
662 			( formatType == CRYPT_FORMAT_PGP ) ? "PGP " : "";
663 	int status;
664 
665 	printf( "Testing %s private key read from %skey file%s...\n",
666 			getAlgoName( cryptAlgo ), keyFileDescr,
667 			useWildcardRead ? " using wildcard ID" : "" );
668 
669 	/* Open the file keyset */
670 	status = cryptKeysetOpen( &cryptKeyset, CRYPT_UNUSED, CRYPT_KEYSET_FILE,
671 							  ( formatType == CRYPT_FORMAT_NONE ) ? \
672 								TEST_PRIVKEY_ALT_FILE : \
673 							  ( formatType == CRYPT_FORMAT_PGP ) ? \
674 								TEST_PRIVKEY_PGP_FILE : TEST_PRIVKEY_FILE,
675 							  CRYPT_KEYOPT_READONLY );
676 	if( cryptStatusError( status ) )
677 		{
678 		if( ( formatType != CRYPT_FORMAT_CRYPTLIB ) && \
679 			( status == CRYPT_ERROR_NOTAVAIL ) )
680 			{
681 			/* If the format isn't supported, this isn't a problem */
682 			puts( "Read of RSA private key from alternative key file "
683 				  "skipped.\n" );
684 			return( TRUE );
685 			}
686 		printf( "cryptKeysetOpen() failed with error code %d, line %d.\n",
687 				status, __LINE__ );
688 		return( FALSE );
689 		}
690 
691 	/* Read the key from the file */
692 	if( formatType == CRYPT_FORMAT_PGP )
693 		{
694 		status = cryptGetPublicKey( cryptKeyset, &cryptContext,
695 									CRYPT_KEYID_NAME, useWildcardRead ? \
696 										TEXT( "[none]" ) : getAlgoLabel( cryptAlgo ) );
697 		}
698 	else
699 		{
700 		status = cryptGetPrivateKey( cryptKeyset, &cryptContext,
701 									 CRYPT_KEYID_NAME, useWildcardRead ? \
702 										TEXT( "[none]" ) : getAlgoLabel( cryptAlgo ),
703 									 TEST_PRIVKEY_PASSWORD );
704 		}
705 	if( cryptStatusError( status ) )
706 		{
707 		printExtError( cryptKeyset, "cryptGetPrivateKey()", status,
708 					   __LINE__ );
709 		return( FALSE );
710 		}
711 
712 	/* Make sure that we can use the read key unless its a PGP key, for
713 	   which we only have the public key */
714 	if( cryptAlgo == CRYPT_ALGO_RSA && formatType != CRYPT_FORMAT_PGP )
715 		{
716 		status = testCrypt( cryptContext, cryptContext, cryptAlgo, NULL,
717 							FALSE, FALSE );
718 		if( cryptStatusError( status ) )
719 			return( FALSE );
720 		}
721 	cryptDestroyContext( cryptContext );
722 
723 	/* Close the keyset */
724 	status = cryptKeysetClose( cryptKeyset );
725 	if( cryptStatusError( status ) )
726 		{
727 		printf( "cryptKeysetClose() failed with error code %d, line %d.\n",
728 				status, __LINE__ );
729 		return( FALSE );
730 		}
731 
732 	printf( "Read of %s private key from %skey file succeeded.\n\n",
733 			getAlgoName( cryptAlgo ), keyFileDescr );
734 	return( TRUE );
735 	}
736 
writeFileKey(const CRYPT_ALGO_TYPE cryptAlgo,const CRYPT_FORMAT_TYPE formatType,const BOOLEAN createFile,const BOOLEAN generateKey)737 static int writeFileKey( const CRYPT_ALGO_TYPE cryptAlgo,
738 						 const CRYPT_FORMAT_TYPE formatType,
739 						 const BOOLEAN createFile,
740 						 const BOOLEAN generateKey )
741 	{
742 	CRYPT_KEYSET cryptKeyset;
743 	CRYPT_CONTEXT privateKeyContext;
744 	const char *keyFileDescr = \
745 			( formatType == CRYPT_FORMAT_NONE ) ? "alternative " : \
746 			( formatType == CRYPT_FORMAT_PGP ) ? "PGP " : "";
747 	int status;
748 
749 	printf( "Testing %s private key write to %skey file...\n",
750 			getAlgoName( cryptAlgo ), keyFileDescr );
751 
752 	/* Create the private key context */
753 	if( generateKey )
754 		{
755 		status = cryptCreateContext( &privateKeyContext, CRYPT_UNUSED,
756 									 cryptAlgo );
757 		if( cryptStatusOK( status ) )
758 			{
759 			status = cryptSetAttributeString( privateKeyContext,
760 											  CRYPT_CTXINFO_LABEL,
761 											  getAlgoLabel( cryptAlgo ),
762 											  paramStrlen( getAlgoLabel( cryptAlgo ) ) );
763 			}
764 		if( cryptStatusOK( status ) )
765 			status = cryptGenerateKey( privateKeyContext );
766 		if( cryptStatusError( status ) )
767 			return( FALSE );
768 		}
769 	else
770 		{
771 		if( !loadPrivateKeyContext( &privateKeyContext, cryptAlgo ) )
772 			return( FALSE );
773 		}
774 
775 	/* Create/open the file keyset.  For the first call (with RSA) we create
776 	   a new keyset, for subsequent calls we update the existing keyset */
777 	status = cryptKeysetOpen( &cryptKeyset, CRYPT_UNUSED, CRYPT_KEYSET_FILE,
778 							  ( formatType == CRYPT_FORMAT_NONE ) ? \
779 								TEST_PRIVKEY_ALT_FILE : \
780 							  ( formatType == CRYPT_FORMAT_PGP ) ? \
781 								TEST_PRIVKEY_PGP_FILE : TEST_PRIVKEY_FILE,
782 								createFile ? CRYPT_KEYOPT_CREATE : \
783 											 CRYPT_KEYOPT_NONE );
784 	if( cryptStatusError( status ) )
785 		{
786 		cryptDestroyContext( privateKeyContext );
787 		if( ( formatType != CRYPT_FORMAT_CRYPTLIB ) && \
788 			( status == CRYPT_ERROR_NOTAVAIL ) )
789 			{
790 			/* If the format isn't supported, this isn't a problem */
791 			puts( "Write of RSA private key to alternative key file "
792 				  "skipped.\n" );
793 			return( TRUE );
794 			}
795 		printf( "cryptKeysetOpen() failed with error code %d, line %d.\n",
796 				status, __LINE__ );
797 		return( FALSE );
798 		}
799 
800 	/* Write the key to the file */
801 	if( formatType == CRYPT_FORMAT_PGP )
802 		status = cryptAddPublicKey( cryptKeyset, privateKeyContext );
803 	else
804 		{
805 		status = cryptAddPrivateKey( cryptKeyset, privateKeyContext,
806 									 TEST_PRIVKEY_PASSWORD );
807 		}
808 	if( cryptStatusError( status ) )
809 		{
810 		printExtError( cryptKeyset, "cryptAddPrivateKey()", status,
811 					   __LINE__ );
812 		return( FALSE );
813 		}
814 
815 	/* Close the keyset */
816 	status = cryptKeysetClose( cryptKeyset );
817 	if( cryptStatusError( status ) )
818 		{
819 		printf( "cryptKeysetClose() failed with error code %d, line %d.\n",
820 				status, __LINE__ );
821 		return( FALSE );
822 		}
823 
824 	/* Clean up */
825 	cryptDestroyContext( privateKeyContext );
826 	printf( "Write of %s private key to %skey file succeeded.\n\n",
827 			getAlgoName( cryptAlgo ), keyFileDescr );
828 	return( TRUE );
829 	}
830 
testReadWriteFileKey(void)831 int testReadWriteFileKey( void )
832 	{
833 	if( !writeFileKey( CRYPT_ALGO_RSA, CRYPT_FORMAT_CRYPTLIB, TRUE, FALSE ) )
834 		return( FALSE );
835 	if( !readFileKey( CRYPT_ALGO_RSA, CRYPT_FORMAT_CRYPTLIB, FALSE ) )
836 		return( FALSE );
837 	if( !readFileKey( CRYPT_ALGO_RSA, CRYPT_FORMAT_CRYPTLIB, TRUE ) )
838 		return( FALSE );
839 	if( !writeFileKey( CRYPT_ALGO_DSA, CRYPT_FORMAT_CRYPTLIB, FALSE, FALSE ) )
840 		return( FALSE );
841 	if( !readFileKey( CRYPT_ALGO_DSA, CRYPT_FORMAT_CRYPTLIB, FALSE ) )
842 		return( FALSE );
843 	if( cryptStatusOK( cryptQueryCapability( CRYPT_ALGO_ELGAMAL, NULL ) ) )
844 		{
845 		if( !writeFileKey( CRYPT_ALGO_ELGAMAL, CRYPT_FORMAT_CRYPTLIB, FALSE, FALSE ) )
846 			return( FALSE );
847 		if( !readFileKey( CRYPT_ALGO_ELGAMAL, CRYPT_FORMAT_CRYPTLIB, FALSE ) )
848 			return( FALSE );
849 		}
850 	if( cryptStatusOK( cryptQueryCapability( CRYPT_ALGO_ECDSA, NULL ) ) )
851 		{
852 		if( !writeFileKey( CRYPT_ALGO_ECDSA, CRYPT_FORMAT_CRYPTLIB, FALSE, FALSE ) )
853 			return( FALSE );
854 		if( !readFileKey( CRYPT_ALGO_ECDSA, CRYPT_FORMAT_CRYPTLIB, FALSE ) )
855 			return( FALSE );
856 		}
857 	return( TRUE );
858 	}
859 
testReadWriteAltFileKey(void)860 int testReadWriteAltFileKey( void )
861 	{
862 	/* We use CRYPT_FORMAT_NONE to denote the alternative format to the
863 	   standard PKCS #15 */
864 	if( !writeFileKey( CRYPT_ALGO_RSA, CRYPT_FORMAT_NONE, TRUE, FALSE ) )
865 		return( FALSE );
866 	return( readFileKey( CRYPT_ALGO_RSA, CRYPT_FORMAT_NONE, FALSE ) );
867 	}
868 
testReadWritePGPFileKey(void)869 int testReadWritePGPFileKey( void )
870 	{
871 	/* To display the written keyring data:
872 
873 		gpg --list-sigs --keyring .\test.pgp
874 		gpg --check-sigs --keyring .\test.pgp
875 		gpg --list-keys --keyring .\test.pgp */
876 	if( !writeFileKey( CRYPT_ALGO_RSA, CRYPT_FORMAT_PGP, TRUE, FALSE ) )
877 		return( FALSE );
878 	return( readFileKey( CRYPT_ALGO_RSA, CRYPT_FORMAT_PGP, FALSE ) );
879 	}
880 
fileKeyImport(const int fileNo)881 static int fileKeyImport( const int fileNo )
882 	{
883 	CRYPT_KEYSET cryptKeyset;
884 	CRYPT_CONTEXT cryptContext;
885 	BYTE buffer[ BUFFER_SIZE ];
886 	int status;
887 
888 	printf( "Testing PKCS #15 file #%d import...\n", fileNo );
889 
890 	/* Open the file keyset */
891 	filenameFromTemplate( buffer, P15_FILE_TEMPLATE, fileNo );
892 	status = cryptKeysetOpen( &cryptKeyset, CRYPT_UNUSED, CRYPT_KEYSET_FILE,
893 							  buffer, CRYPT_KEYOPT_READONLY );
894 	if( fileNo == 1 && status == CRYPT_ERROR_OVERFLOW )
895 		{
896 		/* Depending on the setting of MAX_PKCS15_OBJECTS this keyset may
897 		   contain too many keys to be read, if we get an overflow error we
898 		   continue normally */
899 		printf( "Keyset contains too many items to read, line %d.\n  (This "
900 				"is an expected condition, continuing...).\n", __LINE__ );
901 		return( TRUE );
902 		}
903 	if( fileNo == 2 && status == CRYPT_ERROR_BADDATA )
904 		{
905 		/* This test file is from a pre-release implementation and may not
906 		   necessarily be correct so we don't complain in the case of
907 		   errors */
908 		puts( "Skipping keyset containing specil-case data values." );
909 		return( TRUE );
910 		}
911 	if( cryptStatusError( status ) )
912 		{
913 		printf( "cryptKeysetOpen() failed with error code %d, line %d.\n",
914 				status, __LINE__ );
915 		return( FALSE );
916 		}
917 
918 	/* Read the key from the file */
919 	if( fileNo == 1 )
920 		{
921 		status = cryptGetPrivateKey( cryptKeyset, &cryptContext,
922 									 CRYPT_KEYID_NAME, TEXT( "John Smith 0" ),
923 									 TEXT( "password" ) );
924 		}
925 	else
926 		{
927 		status = cryptGetPrivateKey( cryptKeyset, &cryptContext,
928 									 CRYPT_KEYID_NAME, TEXT( "key and chain" ),
929 									 TEXT( "password" ) );
930 		}
931 	if( cryptStatusError( status ) )
932 		{
933 		printExtError( cryptKeyset, "cryptGetPrivateKey()", status,
934 					   __LINE__ );
935 		return( FALSE );
936 		}
937 	cryptDestroyContext( cryptContext );
938 
939 	/* Close the keyset */
940 	status = cryptKeysetClose( cryptKeyset );
941 	if( cryptStatusError( status ) )
942 		{
943 		printf( "cryptKeysetClose() failed with error code %d, line %d.\n",
944 				status, __LINE__ );
945 		return( FALSE );
946 		}
947 
948 	return( TRUE );
949 	}
950 
testImportFileKey(void)951 int testImportFileKey( void )
952 	{
953 #if 0	/* Disabled until we can get valid third-party PKCS #15 test data */
954 	int i;
955 
956 	for( i = 1; i <= 1; i++ )
957 		{
958 		if( !fileKeyImport( i ) )
959 			return( FALSE );
960 		}
961 #endif /* 0 */
962 
963 	return( TRUE );
964 	}
965 
966 /* Read only the public key/certificate/certificate chain portion of a
967    keyset */
968 
testReadFilePublicKey(void)969 int testReadFilePublicKey( void )
970 	{
971 	CRYPT_KEYSET cryptKeyset;
972 	CRYPT_CONTEXT cryptContext;
973 	int cryptAlgo, status;
974 
975 	puts( "Testing public key read from key file..." );
976 
977 	/* Open the file keyset */
978 	status = cryptKeysetOpen( &cryptKeyset, CRYPT_UNUSED, CRYPT_KEYSET_FILE,
979 							  TEST_PRIVKEY_FILE, CRYPT_KEYOPT_READONLY );
980 	if( cryptStatusError( status ) )
981 		{
982 		printf( "cryptKeysetOpen() failed with error code %d, line %d.\n",
983 				status, __LINE__ );
984 		return( FALSE );
985 		}
986 
987 	/* Read the public key from the file and make sure that it really is a
988 	   public-key context */
989 	status = cryptGetPublicKey( cryptKeyset, &cryptContext, CRYPT_KEYID_NAME,
990 								RSA_PRIVKEY_LABEL );
991 	if( cryptStatusError( status ) )
992 		{
993 		printExtError( cryptKeyset, "cryptGetPublicKey()", status,
994 					   __LINE__ );
995 		return( FALSE );
996 		}
997 	status = cryptGetAttribute( cryptContext, CRYPT_CTXINFO_ALGO, &cryptAlgo );
998 	if( cryptStatusError( status ) || \
999 		cryptAlgo < CRYPT_ALGO_FIRST_PKC || cryptAlgo > CRYPT_ALGO_LAST_PKC )
1000 		{
1001 		puts( "Returned object isn't a public-key context." );
1002 		return( FALSE );
1003 		}
1004 
1005 	/* Close the keyset */
1006 	status = cryptKeysetClose( cryptKeyset );
1007 	if( cryptStatusError( status ) )
1008 		{
1009 		printf( "cryptKeysetClose() failed with error code %d, line %d.\n",
1010 				status, __LINE__ );
1011 		return( FALSE );
1012 		}
1013 
1014 	cryptDestroyContext( cryptContext );
1015 
1016 	puts( "Read of public key from key file succeeded.\n" );
1017 	return( TRUE );
1018 	}
1019 
readCert(const char * certTypeName,const CRYPT_CERTTYPE_TYPE certType,const BOOLEAN readPrivateKey)1020 static int readCert( const char *certTypeName,
1021 					 const CRYPT_CERTTYPE_TYPE certType,
1022 					 const BOOLEAN readPrivateKey )
1023 	{
1024 	CRYPT_KEYSET cryptKeyset;
1025 	int value, status;
1026 
1027 	printf( "Testing %s read from key file...\n", certTypeName );
1028 
1029 	/* Open the file keyset */
1030 	status = cryptKeysetOpen( &cryptKeyset, CRYPT_UNUSED, CRYPT_KEYSET_FILE,
1031 							  TEST_PRIVKEY_FILE, CRYPT_KEYOPT_READONLY );
1032 	if( cryptStatusError( status ) )
1033 		{
1034 		printf( "cryptKeysetOpen() failed with error code %d, line %d.\n",
1035 				status, __LINE__ );
1036 		return( FALSE );
1037 		}
1038 
1039 	/* Read the certificate from the file and make sure that it really is a
1040 	   certificate */
1041 	if( readPrivateKey )
1042 		{
1043 		CRYPT_CONTEXT cryptContext;
1044 
1045 		status = cryptGetPrivateKey( cryptKeyset, &cryptContext,
1046 									 CRYPT_KEYID_NAME, RSA_PRIVKEY_LABEL,
1047 									 TEST_PRIVKEY_PASSWORD );
1048 		if( cryptStatusError( status ) )
1049 			{
1050 			printExtError( cryptKeyset, "cryptGetPrivateKey()", status,
1051 						   __LINE__ );
1052 			return( FALSE );
1053 			}
1054 		if( !checkCertPresence( cryptContext, certTypeName, certType ) )
1055 			return( FALSE );
1056 		cryptDestroyContext( cryptContext );
1057 		}
1058 	else
1059 		{
1060 		CRYPT_CERTIFICATE cryptCert;
1061 
1062 		status = cryptGetPublicKey( cryptKeyset, &cryptCert, CRYPT_KEYID_NAME,
1063 									( certType == CRYPT_CERTTYPE_CERTIFICATE ) ? \
1064 									RSA_PRIVKEY_LABEL : USER_PRIVKEY_LABEL );
1065 		if( cryptStatusError( status ) )
1066 			{
1067 			printExtError( cryptKeyset, "cryptGetPublicKey()", status,
1068 						   __LINE__ );
1069 			return( FALSE );
1070 			}
1071 		status = cryptGetAttribute( cryptCert, CRYPT_CERTINFO_CERTTYPE, &value );
1072 		if( cryptStatusError( status ) || value != certType )
1073 			{
1074 			printf( "Returned object isn't a %s, line %d.\n", certTypeName,
1075 					__LINE__ );
1076 			return( FALSE );
1077 			}
1078 		cryptDestroyCert( cryptCert );
1079 		}
1080 
1081 	/* Close the keyset */
1082 	status = cryptKeysetClose( cryptKeyset );
1083 	if( cryptStatusError( status ) )
1084 		{
1085 		printf( "cryptKeysetClose() failed with error code %d, line %d.\n",
1086 				status, __LINE__ );
1087 		return( FALSE );
1088 		}
1089 
1090 	printf( "Read of %s from key file succeeded.\n\n", certTypeName );
1091 	return( TRUE );
1092 	}
1093 
testReadFileCert(void)1094 int testReadFileCert( void )
1095 	{
1096 	return( readCert( "certificate", CRYPT_CERTTYPE_CERTIFICATE, FALSE ) );
1097 	}
testReadFileCertPrivkey(void)1098 int testReadFileCertPrivkey( void )
1099 	{
1100 	return( readCert( "private key with certificate", CRYPT_CERTTYPE_CERTIFICATE, TRUE ) );
1101 	}
testReadFileCertChain(void)1102 int testReadFileCertChain( void )
1103 	{
1104 	return( readCert( "certificate chain", CRYPT_CERTTYPE_CERTCHAIN, FALSE ) );
1105 	}
1106 
1107 /* Test the ability to detect key data corruption/modification */
1108 
testReadCorruptedKey(void)1109 int testReadCorruptedKey( void )
1110 	{
1111 	CRYPT_KEYSET cryptKeyset;
1112 	CRYPT_CONTEXT cryptContext;
1113 	int i, status;
1114 
1115 	puts( "Testing detection of key corruption in key file..." );
1116 	for( i = 0; i < 4; i++ )
1117 		{
1118 		/* Copy the file to a temporary one, corrupting a data byte in the
1119 		   process */
1120 		status = copyModifiedFile( TEST_PRIVKEY_FILE, TEST_PRIVKEY_TMP_FILE,
1121 								   256 );
1122 		if( !status )
1123 			{
1124 			printf( "Couldn't copy keyset to temporary file, line %d.\n",
1125 					__LINE__ );
1126 			return( FALSE );
1127 			}
1128 
1129 		/* Try and read the key.  The open should succeed, the read should
1130 		   fail */
1131 		status = cryptKeysetOpen( &cryptKeyset, CRYPT_UNUSED,
1132 								  CRYPT_KEYSET_FILE, TEST_PRIVKEY_TMP_FILE,
1133 								  CRYPT_KEYOPT_READONLY );
1134 		if( cryptStatusError( status ) )
1135 			{
1136 			printf( "cryptKeysetOpen() failed with error code %d, line %d.\n",
1137 					status, __LINE__ );
1138 			return( FALSE );
1139 			}
1140 		status = cryptGetPrivateKey( cryptKeyset, &cryptContext,
1141 									 CRYPT_KEYID_NAME, RSA_PRIVKEY_LABEL,
1142 									 TEST_PRIVKEY_PASSWORD );
1143 		if( cryptStatusOK( status ) )
1144 			{
1145 			cryptDestroyContext( cryptContext );
1146 			printf( "Read of corrupted key succeeded when it should have "
1147 					"failed, line %d.\n", __LINE__ );
1148 			return( FALSE );
1149 			}
1150 		cryptKeysetClose( cryptKeyset );
1151 		}
1152 	puts( "Detection of key corruption succeeded.\n" );
1153 
1154 	return( TRUE );
1155 	}
1156 
1157 /****************************************************************************
1158 *																			*
1159 *							Certificate Read/Write Tests					*
1160 *																			*
1161 ****************************************************************************/
1162 
1163 /* Update a keyset to contain a certificate */
1164 
testAddTrustedCert(void)1165 int testAddTrustedCert( void )
1166 	{
1167 	CRYPT_KEYSET cryptKeyset;
1168 	CRYPT_CERTIFICATE trustedCert;
1169 	int value, status;
1170 
1171 	puts( "Testing trusted certificate add to key file..." );
1172 
1173 	/* Read the CA root certificate.  We have to make it explicitly non-
1174 	   trusted since something else may have made it trusted previously */
1175 	status = importCertFromTemplate( &trustedCert, CERT_FILE_TEMPLATE, 1 );
1176 	if( cryptStatusError( status ) )
1177 		{
1178 		puts( "Couldn't read certificate from file, skipping test of trusted "
1179 			  "certificate write..." );
1180 		return( TRUE );
1181 		}
1182 	status = cryptGetAttribute( trustedCert, CRYPT_CERTINFO_TRUSTED_IMPLICIT,
1183 								&value );
1184 	if( cryptStatusOK( status ) && value )
1185 		{
1186 		cryptSetAttribute( trustedCert, CRYPT_CERTINFO_TRUSTED_IMPLICIT,
1187 						   FALSE );
1188 		}
1189 
1190 	/* Open the keyset, update it with the trusted certificate, and close it.
1191 	   Before we make the certificate trusted, we try adding it as a standard
1192 	   certificate, which should fail */
1193 	status = cryptKeysetOpen( &cryptKeyset, CRYPT_UNUSED, CRYPT_KEYSET_FILE,
1194 							  TEST_PRIVKEY_FILE, CRYPT_KEYOPT_CREATE );
1195 	if( cryptStatusError( status ) )
1196 		{
1197 		printf( "cryptKeysetOpen() failed with error code %d, line %d.\n",
1198 				status, __LINE__ );
1199 		return( FALSE );
1200 		}
1201 	status = cryptAddPublicKey( cryptKeyset, trustedCert );
1202 	if( cryptStatusOK( status ) )
1203 		{
1204 		printf( "cryptAddPublicKey() of non-trusted certificate succeeded "
1205 				"when it should have failed, line %d.\n", __LINE__ );
1206 		return( FALSE );
1207 		}
1208 	cryptSetAttribute( trustedCert, CRYPT_CERTINFO_TRUSTED_IMPLICIT, TRUE );
1209 	status = cryptAddPublicKey( cryptKeyset, trustedCert );
1210 	if( cryptStatusError( status ) )
1211 		{
1212 		printExtError( cryptKeyset, "cryptAddPublicKey()", status,
1213 					   __LINE__ );
1214 		return( FALSE );
1215 		}
1216 	cryptSetAttribute( trustedCert, CRYPT_CERTINFO_TRUSTED_IMPLICIT, value );
1217 	cryptDestroyCert( trustedCert );
1218 	status = cryptKeysetClose( cryptKeyset );
1219 	if( cryptStatusError( status ) )
1220 		{
1221 		printf( "cryptKeysetClose() failed with error code %d, line %d.\n",
1222 				status, __LINE__ );
1223 		return( FALSE );
1224 		}
1225 
1226 	puts( "Trusted certificate add to key file succeeded.\n" );
1227 	return( TRUE );
1228 	}
1229 
testAddGloballyTrustedCert(void)1230 int testAddGloballyTrustedCert( void )
1231 	{
1232 	CRYPT_CERTIFICATE trustedCert;
1233 	int status;
1234 
1235 	puts( "Testing globally trusted certificate add..." );
1236 
1237 	/* Read the CA root certificate and make it trusted */
1238 	status = importCertFromTemplate( &trustedCert, CERT_FILE_TEMPLATE, 1 );
1239 	if( cryptStatusError( status ) )
1240 		{
1241 		puts( "Couldn't read certificate from file, skipping test of trusted "
1242 			  "certificate write..." );
1243 		return( TRUE );
1244 		}
1245 	cryptSetAttribute( trustedCert, CRYPT_CERTINFO_TRUSTED_IMPLICIT, TRUE );
1246 
1247 	/* Update the config file with the globally trusted certificate */
1248 	status = cryptSetAttribute( CRYPT_UNUSED, CRYPT_OPTION_CONFIGCHANGED,
1249 								FALSE );
1250 	if( cryptStatusError( status ) )
1251 		{
1252 		printf( "Globally trusted certificate add failed with error code "
1253 				"%d, line %d.\n", status, __LINE__ );
1254 		return( FALSE );
1255 		}
1256 
1257 	/* Make the certificate untrusted and update the config again */
1258 	cryptSetAttribute( trustedCert, CRYPT_CERTINFO_TRUSTED_IMPLICIT, FALSE );
1259 	status = cryptSetAttribute( CRYPT_UNUSED, CRYPT_OPTION_CONFIGCHANGED,
1260 								FALSE );
1261 	if( cryptStatusError( status ) )
1262 		{
1263 		printf( "Globally trusted certificate delete failed with error code "
1264 				"%d, line %d.\n", status, __LINE__ );
1265 		return( FALSE );
1266 		}
1267 
1268 	puts( "Globally trusted certificate add succeeded.\n" );
1269 	return( TRUE );
1270 	}
1271 
1272 static const CERT_DATA FAR_BSS cACertData[] = {
1273 	/* Identification information.  Note the non-heirarchical order of the
1274 	   components to test the automatic arranging of the DN */
1275 	{ CRYPT_CERTINFO_ORGANIZATIONNAME, IS_STRING, 0, TEXT( "Dave's Wetaburgers and CA" ) },
1276 	{ CRYPT_CERTINFO_COMMONNAME, IS_STRING, 0, TEXT( "Dave Himself" ) },
1277 	{ CRYPT_CERTINFO_ORGANIZATIONALUNITNAME, IS_STRING, 0, TEXT( "Certification Division" ) },
1278 	{ CRYPT_CERTINFO_COUNTRYNAME, IS_STRING, 0, TEXT( "NZ" ) },
1279 
1280 	/* Self-signed X.509v3 certificate */
1281 	{ CRYPT_CERTINFO_SELFSIGNED, IS_NUMERIC, TRUE },
1282 
1283 	/* CA key usage */
1284 	{ CRYPT_CERTINFO_KEYUSAGE, IS_NUMERIC,
1285 	  CRYPT_KEYUSAGE_KEYCERTSIGN | CRYPT_KEYUSAGE_CRLSIGN },
1286 	{ CRYPT_CERTINFO_CA, IS_NUMERIC, TRUE },
1287 
1288 	{ CRYPT_ATTRIBUTE_NONE, IS_VOID }
1289 	};
1290 
testUpdateFileCert(void)1291 int testUpdateFileCert( void )
1292 	{
1293 	CRYPT_KEYSET cryptKeyset;
1294 	CRYPT_CERTIFICATE cryptCert;
1295 	CRYPT_CONTEXT publicKeyContext, privateKeyContext;
1296 	int status;
1297 
1298 	puts( "Testing certificate update to key file ..." );
1299 
1300 	/* Create a self-signed CA certificate using the in-memory key (which is
1301 	   the same as the one in the keyset) */
1302 	if( !loadRSAContexts( CRYPT_UNUSED, &publicKeyContext, &privateKeyContext ) )
1303 		return( FALSE );
1304 	status = cryptCreateCert( &cryptCert, CRYPT_UNUSED,
1305 							  CRYPT_CERTTYPE_CERTIFICATE );
1306 	if( cryptStatusError( status ) )
1307 		{
1308 		printf( "cryptCreateCert() failed with error code %d, line %d.\n",
1309 				status, __LINE__ );
1310 		return( FALSE );
1311 		}
1312 	status = cryptSetAttribute( cryptCert,
1313 						CRYPT_CERTINFO_SUBJECTPUBLICKEYINFO, publicKeyContext );
1314 	if( cryptStatusOK( status ) && \
1315 		!addCertFields( cryptCert, cACertData, __LINE__ ) )
1316 		return( FALSE );
1317 	if( cryptStatusOK( status ) )
1318 		status = cryptSignCert( cryptCert, privateKeyContext );
1319 	destroyContexts( CRYPT_UNUSED, publicKeyContext, privateKeyContext );
1320 	if( cryptStatusError( status ) )
1321 		{
1322 		printf( "Certificate creation failed with error code %d, "
1323 				"line %d.\n", status, __LINE__ );
1324 		cryptDestroyCert( status );
1325 		return( FALSE );
1326 		}
1327 
1328 	/* Open the keyset, update it with the certificate, and close it */
1329 	status = cryptKeysetOpen( &cryptKeyset, CRYPT_UNUSED, CRYPT_KEYSET_FILE,
1330 							  TEST_PRIVKEY_FILE, CRYPT_KEYOPT_NONE );
1331 	if( cryptStatusError( status ) )
1332 		{
1333 		printf( "cryptKeysetOpen() failed with error code %d, line %d.\n",
1334 				status, __LINE__ );
1335 		return( FALSE );
1336 		}
1337 	status = cryptAddPublicKey( cryptKeyset, cryptCert );
1338 	if( cryptStatusError( status ) )
1339 		{
1340 		printExtError( cryptKeyset, "cryptAddPublicKey()", status,
1341 					   __LINE__ );
1342 		return( FALSE );
1343 		}
1344 	cryptDestroyCert( cryptCert );
1345 	status = cryptKeysetClose( cryptKeyset );
1346 	if( cryptStatusError( status ) )
1347 		{
1348 		printf( "cryptKeysetClose() failed with error code %d, line %d.\n",
1349 				status, __LINE__ );
1350 		return( FALSE );
1351 		}
1352 
1353 	puts( "Certificate update to key file succeeded.\n" );
1354 	return( TRUE );
1355 	}
1356 
1357 /* Update a keyset to contain a certificate chain */
1358 
writeFileCertChain(const CERT_DATA * certRequestData,const C_STR keyFileName,const C_STR certFileName,const BOOLEAN isTestRun,const BOOLEAN writeLongChain,const CRYPT_ALGO_TYPE cryptAlgo,const int keySize)1359 static int writeFileCertChain( const CERT_DATA *certRequestData,
1360 							   const C_STR keyFileName,
1361 							   const C_STR certFileName,
1362 							   const BOOLEAN isTestRun,
1363 							   const BOOLEAN writeLongChain,
1364 							   const CRYPT_ALGO_TYPE cryptAlgo,
1365 							   const int keySize )
1366 	{
1367 	CRYPT_KEYSET cryptKeyset;
1368 	CRYPT_CERTIFICATE cryptCertChain;
1369 	CRYPT_CONTEXT cryptCAKey, cryptKey;
1370 	int status;
1371 
1372 	if( isTestRun )
1373 		{
1374 		printf( "Testing %scert chain write to key file ...\n",
1375 				writeLongChain ? "long " : "" );
1376 		}
1377 
1378 	/* Generate a key to certify.  We can't just reuse the built-in test key
1379 	   because this has already been used as the CA key and the keyset code
1380 	   won't allow it to be added to a keyset as both a CA key and user key,
1381 	   so we have to generate a new one */
1382 	status = cryptCreateContext( &cryptKey, CRYPT_UNUSED, cryptAlgo );
1383 	if( cryptStatusOK( status ) && keySize != CRYPT_USE_DEFAULT )
1384 		status = cryptSetAttribute( cryptKey, CRYPT_CTXINFO_KEYSIZE,
1385 									keySize );
1386 	if( cryptStatusOK( status ) )
1387 		{
1388 		status = cryptSetAttributeString( cryptKey, CRYPT_CTXINFO_LABEL,
1389 										  USER_PRIVKEY_LABEL,
1390 										  paramStrlen( USER_PRIVKEY_LABEL ) );
1391 		}
1392 	if( cryptStatusOK( status ) )
1393 		status = cryptGenerateKey( cryptKey );
1394 	if( cryptStatusError( status ) )
1395 		{
1396 		printf( "Test key generation failed with error code %d, line %d.\n",
1397 				status, __LINE__ );
1398 		return( FALSE );
1399 		}
1400 
1401 	/* Get the CA's key.  The length of the chain is determined by the
1402 	   number of certs attached to the CAs certificate, so handling long vs.
1403 	   short chains is pretty simple */
1404 	if( writeLongChain )
1405 		status = getPrivateKey( &cryptCAKey, ICA_PRIVKEY_FILE,
1406 								USER_PRIVKEY_LABEL, TEST_PRIVKEY_PASSWORD );
1407 	else
1408 		status = getPrivateKey( &cryptCAKey, CA_PRIVKEY_FILE,
1409 								CA_PRIVKEY_LABEL, TEST_PRIVKEY_PASSWORD );
1410 	if( cryptStatusError( status ) )
1411 		{
1412 		printf( "CA private key read failed with error code %d, line %d.\n",
1413 				status, __LINE__ );
1414 		return( FALSE );
1415 		}
1416 
1417 	/* Create the keyset and add the private key to it */
1418 	status = cryptKeysetOpen( &cryptKeyset, CRYPT_UNUSED, CRYPT_KEYSET_FILE,
1419 							  keyFileName, CRYPT_KEYOPT_CREATE );
1420 	if( cryptStatusError( status ) )
1421 		{
1422 		printf( "cryptKeysetOpen() failed with error code %d, line %d.\n",
1423 				status, __LINE__ );
1424 		return( FALSE );
1425 		}
1426 	status = cryptAddPrivateKey( cryptKeyset, cryptKey,
1427 								 TEST_PRIVKEY_PASSWORD );
1428 	if( cryptStatusError( status ) )
1429 		{
1430 		printExtError( cryptKeyset, "cryptAddPrivateKey()", status,
1431 					   __LINE__ );
1432 		return( FALSE );
1433 		}
1434 
1435 	/* Create the certificate chain for the new key */
1436 	status = cryptCreateCert( &cryptCertChain, CRYPT_UNUSED,
1437 							  CRYPT_CERTTYPE_CERTCHAIN );
1438 	if( cryptStatusOK( status ) )
1439 		status = cryptSetAttribute( cryptCertChain,
1440 							CRYPT_CERTINFO_SUBJECTPUBLICKEYINFO, cryptKey );
1441 	cryptDestroyContext( cryptKey );
1442 	if( cryptStatusOK( status ) && \
1443 		!addCertFields( cryptCertChain, certRequestData, __LINE__ ) )
1444 		return( FALSE );
1445 #ifndef _WIN32_WCE	/* Windows CE doesn't support ANSI C time functions */
1446 	if( cryptStatusOK( status ) && !isTestRun )
1447 		{
1448 		const time_t validity = time( NULL ) + ( 86400L * 365 * 3 );
1449 
1450 		/* Make it valid for 5 years instead of 1 to avoid problems when
1451 		   users run the self-test with very old copies of the code */
1452 		status = cryptSetAttributeString( cryptCertChain,
1453 					CRYPT_CERTINFO_VALIDTO, &validity, sizeof( time_t ) );
1454 		}
1455 #endif /* WinCE */
1456 	if( cryptStatusOK( status ) )
1457 		status = cryptSignCert( cryptCertChain, cryptCAKey );
1458 	cryptDestroyContext( cryptCAKey );
1459 	if( cryptStatusError( status ) )
1460 		{
1461 		printf( "Certificate chain creation failed with error code %d, "
1462 				"line %d.\n", status, __LINE__ );
1463 		printErrorAttributeInfo( cryptCertChain );
1464 		return( FALSE );
1465 		}
1466 
1467 	/* Add the certificate chain to the file */
1468 	status = cryptAddPublicKey( cryptKeyset, cryptCertChain );
1469 	if( cryptStatusError( status ) )
1470 		{
1471 		printExtError( cryptKeyset, "cryptAddPrivateKey()", status,
1472 					   __LINE__ );
1473 		return( FALSE );
1474 		}
1475 	if( certFileName != NULL )
1476 		{
1477 		FILE *filePtr;
1478 		BYTE certBuffer[ BUFFER_SIZE ];
1479 		int length;
1480 
1481 		/* Save the certificate to disk for use in request/response
1482 		   protocols */
1483 		status = cryptExportCert( certBuffer, BUFFER_SIZE, &length,
1484 								  CRYPT_CERTFORMAT_CERTIFICATE,
1485 								  cryptCertChain );
1486 		if( cryptStatusError( status ) )
1487 			{
1488 			printf( "cryptExportCert() failed with error code %d, "
1489 					"line %d.\n", status, __LINE__ );
1490 			return( FALSE );
1491 			}
1492 		if( ( filePtr = fopen( convertFileName( certFileName ), \
1493 							   "wb" ) ) != NULL )
1494 			{
1495 			int count;
1496 
1497 			count = fwrite( certBuffer, 1, length, filePtr );
1498 			fclose( filePtr );
1499 			if( count < length )
1500 				{
1501 				remove( convertFileName( certFileName ) );
1502 				puts( "Warning: Couldn't save certificate chain to disk, "
1503 					  "this will cause later\n         tests to fail.  "
1504 					  "Press a key to continue." );
1505 				getchar();
1506 				}
1507 			}
1508 		}
1509 	cryptDestroyCert( cryptCertChain );
1510 	status = cryptKeysetClose( cryptKeyset );
1511 	if( cryptStatusError( status ) )
1512 		{
1513 		printf( "cryptKeysetClose() failed with error code %d, line %d.\n",
1514 				status, __LINE__ );
1515 		return( FALSE );
1516 		}
1517 
1518 	if( isTestRun )
1519 		puts( "Certificate chain write to key file succeeded.\n" );
1520 	return( TRUE );
1521 	}
1522 
1523 static const CERT_DATA FAR_BSS certRequestData[] = {
1524 	/* Identification information */
1525 	{ CRYPT_CERTINFO_COUNTRYNAME, IS_STRING, 0, TEXT( "NZ" ) },
1526 	{ CRYPT_CERTINFO_ORGANIZATIONNAME, IS_STRING, 0, TEXT( "Dave's Wetaburgers" ) },
1527 	{ CRYPT_CERTINFO_ORGANIZATIONALUNITNAME, IS_STRING, 0, TEXT( "Procurement" ) },
1528 	{ CRYPT_CERTINFO_COMMONNAME, IS_STRING, 0, TEXT( "Dave Smith" ) },
1529 	{ CRYPT_CERTINFO_EMAIL, IS_STRING, 0, TEXT( "dave@wetaburgers.com" ) },
1530 	{ CRYPT_ATTRIBUTE_CURRENT, IS_NUMERIC, CRYPT_CERTINFO_SUBJECTNAME },	/* Re-select subject DN */
1531 
1532 	{ CRYPT_ATTRIBUTE_NONE, 0, 0, NULL }
1533 	};
1534 
testWriteFileCertChain(void)1535 int testWriteFileCertChain( void )
1536 	{
1537 	return( writeFileCertChain( certRequestData, TEST_PRIVKEY_FILE, NULL,
1538 								TRUE, FALSE, CRYPT_ALGO_RSA,
1539 								CRYPT_USE_DEFAULT ) );
1540 	}
1541 
testWriteFileLongCertChain(void)1542 int testWriteFileLongCertChain( void )
1543 	{
1544 	return( writeFileCertChain( certRequestData, TEST_PRIVKEY_FILE, NULL,
1545 								TRUE, TRUE, CRYPT_ALGO_RSA,
1546 								CRYPT_USE_DEFAULT ) );
1547 	}
1548 
1549 /* Delete a key from a file */
1550 
testDeleteFileKey(void)1551 int testDeleteFileKey( void )
1552 	{
1553 	CRYPT_KEYSET cryptKeyset;
1554 	CRYPT_CONTEXT cryptContext;
1555 	int status;
1556 
1557 	puts( "Testing delete from key file..." );
1558 
1559 	/* Open the file keyset */
1560 	status = cryptKeysetOpen( &cryptKeyset, CRYPT_UNUSED, CRYPT_KEYSET_FILE,
1561 							  TEST_PRIVKEY_FILE, CRYPT_KEYOPT_NONE );
1562 	if( cryptStatusError( status ) )
1563 		{
1564 		printf( "cryptKeysetOpen() failed with error code %d, line %d.\n",
1565 				status, __LINE__ );
1566 		return( FALSE );
1567 		}
1568 
1569 	/* Delete the key from the file.  Since we don't need the DSA key any
1570 	   more we use it as the key to delete */
1571 	status = cryptDeleteKey( cryptKeyset, CRYPT_KEYID_NAME,
1572 							 DSA_PRIVKEY_LABEL );
1573 	if( cryptStatusError( status ) )
1574 		{
1575 		printExtError( cryptKeyset, "cryptDeletePrivateKey()", status,
1576 					   __LINE__ );
1577 		return( FALSE );
1578 		}
1579 	status = cryptGetPublicKey( cryptKeyset, &cryptContext, CRYPT_KEYID_NAME,
1580 								DSA_PRIVKEY_LABEL );
1581 	if( cryptStatusOK( status ) )
1582 		{
1583 		cryptDestroyContext( cryptContext );
1584 		puts( "cryptDeleteKey() claimed the key was deleted but it's still "
1585 			  "present." );
1586 		return( FALSE );
1587 		}
1588 
1589 	/* Close the keyset */
1590 	status = cryptKeysetClose( cryptKeyset );
1591 	if( cryptStatusError( status ) )
1592 		{
1593 		printf( "cryptKeysetClose() failed with error code %d, line %d.\n",
1594 				status, __LINE__ );
1595 		return( FALSE );
1596 		}
1597 
1598 	puts( "Delete from key file succeeded.\n" );
1599 	return( TRUE );
1600 	}
1601 
1602 /* Change the password for a key in a file */
1603 
testChangeFileKeyPassword(void)1604 int testChangeFileKeyPassword( void )
1605 	{
1606 	CRYPT_KEYSET cryptKeyset;
1607 	CRYPT_CONTEXT cryptContext;
1608 	int status;
1609 
1610 	puts( "Testing change of key password for key file..." );
1611 
1612 	/* Open the file keyset */
1613 	status = cryptKeysetOpen( &cryptKeyset, CRYPT_UNUSED, CRYPT_KEYSET_FILE,
1614 							  TEST_PRIVKEY_FILE, CRYPT_KEYOPT_NONE );
1615 	if( cryptStatusError( status ) )
1616 		{
1617 		printf( "cryptKeysetOpen() failed with error code %d, line %d.\n",
1618 				status, __LINE__ );
1619 		return( FALSE );
1620 		}
1621 
1622 	/* Read the key using the old password, delete it, and write it back
1623 	   using the new password.  To keep things simple we just use the same
1624 	   password (since the key will be used again later), the test of the
1625 	   delete function earlier on has already confirmed that the old key
1626 	   and password will be deleted so there's no chance of a false positive */
1627 	status = cryptGetPrivateKey( cryptKeyset, &cryptContext,
1628 								 CRYPT_KEYID_NAME, RSA_PRIVKEY_LABEL,
1629 								 TEST_PRIVKEY_PASSWORD );
1630 	if( cryptStatusOK( status ) )
1631 		status = cryptDeleteKey( cryptKeyset, CRYPT_KEYID_NAME,
1632 								 RSA_PRIVKEY_LABEL );
1633 	if( cryptStatusOK( status ) )
1634 		status = cryptAddPrivateKey( cryptKeyset, cryptContext,
1635 									 TEST_PRIVKEY_PASSWORD );
1636 	if( cryptStatusError( status ) )
1637 		{
1638 		printExtError( cryptKeyset, "password change", status,
1639 					   __LINE__ );
1640 		return( FALSE );
1641 		}
1642 	cryptDestroyContext( cryptContext );
1643 
1644 	/* Close the keyset */
1645 	status = cryptKeysetClose( cryptKeyset );
1646 	if( cryptStatusError( status ) )
1647 		{
1648 		printf( "cryptKeysetClose() failed with error code %d, line %d.\n",
1649 				status, __LINE__ );
1650 		return( FALSE );
1651 		}
1652 
1653 	puts( "Password change for key in key file succeeded.\n" );
1654 	return( TRUE );
1655 	}
1656 
1657 /* Write a key and certificate to a file in a single operation */
1658 
writeSingleStepFileCert(const CRYPT_ALGO_TYPE cryptAlgo,const BOOLEAN useAltKeyFile)1659 static int writeSingleStepFileCert( const CRYPT_ALGO_TYPE cryptAlgo,
1660 									const BOOLEAN useAltKeyFile )
1661 	{
1662 	CRYPT_KEYSET cryptKeyset;
1663 	CRYPT_CERTIFICATE cryptCert;
1664 	CRYPT_CONTEXT cryptContext;
1665 	int status;
1666 
1667 	printf( "Testing single-step %s key+certificate write to %skey file...\n",
1668 			getAlgoName( cryptAlgo ), useAltKeyFile ? "alternative " : "" );
1669 
1670 	/* Create a self-signed CA certificate */
1671 	if( !loadPrivateKeyContext( &cryptContext, cryptAlgo ) )
1672 		return( FALSE );
1673 	status = cryptCreateCert( &cryptCert, CRYPT_UNUSED,
1674 							  CRYPT_CERTTYPE_CERTIFICATE );
1675 	if( cryptStatusError( status ) )
1676 		{
1677 		printf( "cryptCreateCert() failed with error code %d, line %d.\n",
1678 				status, __LINE__ );
1679 		return( FALSE );
1680 		}
1681 	status = cryptSetAttribute( cryptCert,
1682 						CRYPT_CERTINFO_SUBJECTPUBLICKEYINFO, cryptContext );
1683 	if( cryptStatusOK( status ) && \
1684 		!addCertFields( cryptCert, cACertData, __LINE__ ) )
1685 		return( FALSE );
1686 	if( cryptStatusOK( status ) )
1687 		status = cryptSignCert( cryptCert, cryptContext );
1688 	if( cryptStatusError( status ) )
1689 		{
1690 		printf( "Certificate creation failed with error code %d, "
1691 				"line %d.\n", status, __LINE__ );
1692 		cryptDestroyCert( status );
1693 		return( FALSE );
1694 		}
1695 
1696 	/* Open the keyset, write the key and certificate, and close it */
1697 	status = cryptKeysetOpen( &cryptKeyset, CRYPT_UNUSED, CRYPT_KEYSET_FILE,
1698 					useAltKeyFile ? TEST_PRIVKEY_ALT_FILE : TEST_PRIVKEY_FILE,
1699 					CRYPT_KEYOPT_CREATE );
1700 	if( cryptStatusError( status ) )
1701 		{
1702 		cryptDestroyContext( cryptContext );
1703 		cryptDestroyCert( cryptCert );
1704 		if( useAltKeyFile && status == CRYPT_ERROR_NOTAVAIL )
1705 			{
1706 			/* If the format isn't supported, this isn't a problem */
1707 			puts( "Single-step update to alternative key file skipped.\n" );
1708 			return( TRUE );
1709 			}
1710 		printf( "cryptKeysetOpen() failed with error code %d, line %d.\n",
1711 				status, __LINE__ );
1712 		return( FALSE );
1713 		}
1714 	status = cryptAddPrivateKey( cryptKeyset, cryptContext,
1715 								 TEST_PRIVKEY_PASSWORD );
1716 	if( cryptStatusError( status ) )
1717 		{
1718 		printExtError( cryptKeyset, "cryptAddPrivateKey()", status,
1719 					   __LINE__ );
1720 		return( FALSE );
1721 		}
1722 	status = cryptAddPublicKey( cryptKeyset, cryptCert );
1723 	if( cryptStatusError( status ) )
1724 		{
1725 		printExtError( cryptKeyset, "cryptAddPublic/PrivateKey()", status,
1726 					   __LINE__ );
1727 		return( FALSE );
1728 		}
1729 	cryptDestroyContext( cryptContext );
1730 	cryptDestroyCert( cryptCert );
1731 
1732 	/* Try and read the key+certificate back before we close the keyset.
1733 	   This ensures that the in-memory data has been updated correctly */
1734 	status = cryptGetPrivateKey( cryptKeyset, &cryptContext,
1735 								 CRYPT_KEYID_NAME, getAlgoLabel( cryptAlgo ),
1736 								 TEST_PRIVKEY_PASSWORD );
1737 	cryptDestroyContext( cryptContext );
1738 	if( cryptStatusError( status ) )
1739 		{
1740 		cryptKeysetClose( cryptKeyset );
1741 		printExtError( cryptKeyset,
1742 					   "private key read from in-memory cached keyset data",
1743 					   status, __LINE__ );
1744 		return( FALSE );
1745 		}
1746 
1747 	/* Close the keyset, which flushes the in-memory changes to disk.  The
1748 	   cacheing of data in memory ensures that all keyset updates are atomic,
1749 	   so that it's nearly impossible to corrupt a private key keyset during
1750 	   an update */
1751 	status = cryptKeysetClose( cryptKeyset );
1752 	if( cryptStatusError( status ) )
1753 		{
1754 		printf( "cryptKeysetClose() failed with error code %d, line %d.\n",
1755 				status, __LINE__ );
1756 		return( FALSE );
1757 		}
1758 
1759 	/* Try and read the key+certificate back from disk rather than the
1760 	   cached, in-memory version */
1761 	status = getPrivateKey( &cryptContext,
1762 				useAltKeyFile ? TEST_PRIVKEY_ALT_FILE : TEST_PRIVKEY_FILE,
1763 				getAlgoLabel( cryptAlgo ), TEST_PRIVKEY_PASSWORD );
1764 	cryptDestroyContext( cryptContext );
1765 	if( cryptStatusError( status ) )
1766 		{
1767 		printExtError( cryptKeyset,
1768 					   "private key read from on-disk keyset data",
1769 					   status, __LINE__ );
1770 		return( FALSE );
1771 		}
1772 
1773 	printf( "Single-step %s key+certificate write to %skey file succeeded.\n\n",
1774 			getAlgoName( cryptAlgo ), useAltKeyFile ? "alternative " : "" );
1775 	return( TRUE );
1776 	}
1777 
testSingleStepFileCert(void)1778 int testSingleStepFileCert( void )
1779 	{
1780 	if( !writeSingleStepFileCert( CRYPT_ALGO_RSA, FALSE ) )
1781 		return( FALSE );
1782 	if( !writeSingleStepFileCert( CRYPT_ALGO_DSA, FALSE ) )
1783 		return( FALSE );
1784 	if( cryptStatusOK( cryptQueryCapability( CRYPT_ALGO_ECDSA, NULL ) ) && \
1785 		!writeSingleStepFileCert( CRYPT_ALGO_ECDSA, FALSE ) )
1786 		return( FALSE );
1787 	return( TRUE );
1788 	}
1789 
testSingleStepAltFileCert(void)1790 int testSingleStepAltFileCert( void )
1791 	{
1792 	return( writeSingleStepFileCert( CRYPT_ALGO_RSA, TRUE ) );
1793 	}
1794 
1795 /* Write two keys and certs (signature + encryption) with the same DN to a
1796    file */
1797 
testDoubleCertFile(void)1798 int testDoubleCertFile( void )
1799 	{
1800 	CRYPT_KEYSET cryptKeyset;
1801 	CRYPT_CERTIFICATE cryptSigCert, cryptEncryptCert;
1802 	CRYPT_CONTEXT cryptCAKey, cryptSigContext, cryptEncryptContext;
1803 	int status;
1804 
1805 	puts( "Testing separate signature+encryption certificate write to key "
1806 		  "file..." );
1807 	doubleCertOK = FALSE;
1808 
1809 	/* Get the CA's key */
1810 	status = getPrivateKey( &cryptCAKey, CA_PRIVKEY_FILE,
1811 							CA_PRIVKEY_LABEL, TEST_PRIVKEY_PASSWORD );
1812 	if( cryptStatusError( status ) )
1813 		{
1814 		printf( "CA private key read failed with error code %d, line %d.\n",
1815 				status, __LINE__ );
1816 		return( FALSE );
1817 		}
1818 
1819 	/* Generate two keys to certify.  We can't just use the built-in test key
1820 	   because cryptlib will detect it being added to the keyset a second time
1821 	   (if we reuse it for both keys) and because the label is a generic one
1822 	   that doesn't work if there are two keys */
1823 	status = cryptCreateContext( &cryptSigContext, CRYPT_UNUSED,
1824 								 CRYPT_ALGO_RSA );
1825 	if( cryptStatusOK( status ) )
1826 		{
1827 		status = cryptSetAttributeString( cryptSigContext,
1828 							CRYPT_CTXINFO_LABEL, DUAL_SIGNKEY_LABEL,
1829 							paramStrlen( DUAL_SIGNKEY_LABEL ) );
1830 		}
1831 	if( cryptStatusOK( status ) )
1832 		status = cryptGenerateKey( cryptSigContext );
1833 	if( cryptStatusError( status ) )
1834 		{
1835 		printf( "Test key generation failed with error code %d, line %d.\n",
1836 				status, __LINE__ );
1837 		return( FALSE );
1838 		}
1839 	status = cryptCreateContext( &cryptEncryptContext, CRYPT_UNUSED,
1840 								 CRYPT_ALGO_RSA );
1841 	if( cryptStatusOK( status ) )
1842 		status = cryptSetAttributeString( cryptEncryptContext,
1843 							CRYPT_CTXINFO_LABEL, DUAL_ENCRYPTKEY_LABEL,
1844 							paramStrlen( DUAL_ENCRYPTKEY_LABEL ) );
1845 	if( cryptStatusOK( status ) )
1846 		status = cryptGenerateKey( cryptEncryptContext );
1847 	if( cryptStatusError( status ) )
1848 		{
1849 		printf( "Test key generation failed with error code %d, line %d.\n",
1850 				status, __LINE__ );
1851 		return( FALSE );
1852 		}
1853 
1854 	/* Create the certs containing the keys.  In order to avoid clashes with
1855 	   other keys with the same CN in the public-key database, we give the
1856 	   certs abnormal CNs.  This isn't necessary for cryptlib to manage them,
1857 	   but because later code tries to delete leftover certs from previous
1858 	   runs with the generic name used in the self-tests, which would also
1859 	   delete these certs */
1860 	status = cryptCreateCert( &cryptSigCert, CRYPT_UNUSED,
1861 							  CRYPT_CERTTYPE_CERTIFICATE );
1862 	if( cryptStatusOK( status ) )
1863 		status = cryptSetAttribute( cryptSigCert,
1864 					CRYPT_CERTINFO_SUBJECTPUBLICKEYINFO, cryptSigContext );
1865 	if( cryptStatusOK( status ) && \
1866 		!addCertFields( cryptSigCert, certRequestData, __LINE__ ) )
1867 		return( FALSE );
1868 	if( cryptStatusOK( status ) )
1869 		{
1870 		status = cryptDeleteAttribute( cryptSigCert,
1871 									   CRYPT_CERTINFO_COMMONNAME );
1872 		if( cryptStatusOK( status ) )
1873 			{
1874 			status = cryptSetAttributeString( cryptSigCert,
1875 					CRYPT_CERTINFO_COMMONNAME, TEXT( "Dave Smith (Dual)" ),
1876 					paramStrlen( TEXT( "Dave Smith (Dual)" ) ) );
1877 			}
1878 		}
1879 	if( cryptStatusOK( status ) )
1880 		status = cryptSetAttribute( cryptSigCert,
1881 					CRYPT_CERTINFO_KEYUSAGE, CRYPT_KEYUSAGE_DIGITALSIGNATURE );
1882 	if( cryptStatusOK( status ) )
1883 		status = cryptSignCert( cryptSigCert, cryptCAKey );
1884 	if( cryptStatusError( status ) )
1885 		{
1886 		printf( "Signature certificate creation failed with error code %d, "
1887 				"line %d.\n", status, __LINE__ );
1888 		printErrorAttributeInfo( cryptSigCert );
1889 		return( FALSE );
1890 		}
1891 	status = cryptCreateCert( &cryptEncryptCert, CRYPT_UNUSED,
1892 							  CRYPT_CERTTYPE_CERTIFICATE );
1893 	if( cryptStatusOK( status ) )
1894 		status = cryptSetAttribute( cryptEncryptCert,
1895 					CRYPT_CERTINFO_SUBJECTPUBLICKEYINFO, cryptEncryptContext );
1896 	if( cryptStatusOK( status ) && \
1897 		!addCertFields( cryptEncryptCert, certRequestData, __LINE__ ) )
1898 		return( FALSE );
1899 	if( cryptStatusOK( status ) )
1900 		{
1901 		status = cryptDeleteAttribute( cryptEncryptCert,
1902 									   CRYPT_CERTINFO_COMMONNAME );
1903 		if( cryptStatusOK( status ) )
1904 			{
1905 			status = cryptSetAttributeString( cryptEncryptCert,
1906 					CRYPT_CERTINFO_COMMONNAME, TEXT( "Dave Smith (Dual)" ),
1907 					paramStrlen( TEXT( "Dave Smith (Dual)" ) ) );
1908 			}
1909 		}
1910 	if( cryptStatusOK( status ) )
1911 		status = cryptSetAttribute( cryptEncryptCert,
1912 					CRYPT_CERTINFO_KEYUSAGE, CRYPT_KEYUSAGE_KEYENCIPHERMENT );
1913 	if( cryptStatusOK( status ) )
1914 		status = cryptSignCert( cryptEncryptCert, cryptCAKey );
1915 	if( cryptStatusError( status ) )
1916 		{
1917 		printf( "Encryption certificate creation failed with error code %d, "
1918 				"line %d.\n", status, __LINE__ );
1919 		printErrorAttributeInfo( cryptEncryptCert );
1920 		return( FALSE );
1921 		}
1922 	cryptDestroyContext( cryptCAKey );
1923 
1924 	/* Open the keyset, write the keys and certificates, and close it */
1925 	status = cryptKeysetOpen( &cryptKeyset, CRYPT_UNUSED, CRYPT_KEYSET_FILE,
1926 							  DUAL_PRIVKEY_FILE, CRYPT_KEYOPT_CREATE );
1927 	if( cryptStatusError( status ) )
1928 		{
1929 		printf( "cryptKeysetOpen() failed with error code %d, line %d.\n",
1930 				status, __LINE__ );
1931 		return( FALSE );
1932 		}
1933 	status = cryptAddPrivateKey( cryptKeyset, cryptSigContext,
1934 								 TEST_PRIVKEY_PASSWORD );
1935 	if( cryptStatusOK( status ) )
1936 		status = cryptAddPrivateKey( cryptKeyset, cryptEncryptContext,
1937 									 TEST_PRIVKEY_PASSWORD );
1938 	if( cryptStatusError( status ) )
1939 		{
1940 		printExtError( cryptKeyset, "cryptAddPrivateKey()", status,
1941 					   __LINE__ );
1942 		return( FALSE );
1943 		}
1944 	status = cryptAddPublicKey( cryptKeyset, cryptSigCert );
1945 	if( cryptStatusOK( status ) )
1946 		status = cryptAddPublicKey( cryptKeyset, cryptEncryptCert );
1947 	if( cryptStatusError( status ) )
1948 		{
1949 		printExtError( cryptKeyset, "cryptAddPublicKey()", status,
1950 					   __LINE__ );
1951 		return( FALSE );
1952 		}
1953 	status = cryptKeysetClose( cryptKeyset );
1954 	if( cryptStatusError( status ) )
1955 		{
1956 		printf( "cryptKeysetClose() failed with error code %d, line %d.\n",
1957 				status, __LINE__ );
1958 		return( FALSE );
1959 		}
1960 
1961 	/* Write the two certs to a public-key database if there's one available
1962 	   (because it may not be present, we fail quietly if access to this
1963 	   keyset type isn't available or the keyset isn't present, it'll be
1964 	   picked up later by other tests).
1965 
1966 	   This certificate write is needed later to test the encryption vs.
1967 	   signature certificate handling.  Since they may have been added
1968 	   earlier we try and delete them first (we can't use the existing
1969 	   version since the issuerAndSerialNumber won't match the ones in the
1970 	   private-key keyset) */
1971 	status = cryptKeysetOpen( &cryptKeyset, CRYPT_UNUSED,
1972 							  DATABASE_KEYSET_TYPE, DATABASE_KEYSET_NAME,
1973 							  CRYPT_KEYOPT_NONE );
1974 	if( status != CRYPT_ERROR_PARAM3 && status != CRYPT_ERROR_OPEN )
1975 		{
1976 		C_CHR name[ CRYPT_MAX_TEXTSIZE + 1 ];
1977 		int length;
1978 
1979 		if( cryptStatusError( status ) )
1980 			{
1981 			printf( "cryptKeysetOpen() failed with error code %d, line %d.\n",
1982 					status, __LINE__ );
1983 			if( status == CRYPT_ERROR_OPEN )
1984 				return( CRYPT_ERROR_FAILED );
1985 			return( FALSE );
1986 			}
1987 		status = cryptGetAttributeString( cryptSigCert,
1988 										  CRYPT_CERTINFO_COMMONNAME,
1989 										  name, &length );
1990 		if( cryptStatusError( status ) )
1991 			return( FALSE );
1992 #ifdef UNICODE_STRINGS
1993 		length /= sizeof( wchar_t );
1994 #endif /* UNICODE_STRINGS */
1995 		name[ length ] = TEXT( '\0' );
1996 		do
1997 			status = cryptDeleteKey( cryptKeyset, CRYPT_KEYID_NAME, name );
1998 		while( cryptStatusOK( status ) );
1999 		if( status != CRYPT_ERROR_NOTFOUND )
2000 			{
2001 			/* Deletion of the existing keys failed for some reason, we can't
2002 			   continue */
2003 			return( extErrorExit( cryptKeyset, "cryptDeleteKey()",
2004 								  status, __LINE__ ) );
2005 			}
2006 		status = cryptAddPublicKey( cryptKeyset, cryptSigCert );
2007 		if( status != CRYPT_ERROR_NOTFOUND )
2008 			{
2009 			/* We can get a notfound if a database keyset is defined but
2010 			   hasn't been initialised yet so the necessary tables don't
2011 			   exist, it can be opened but an attempt to add a key will
2012 			   return a not found error since it's the table itself rather
2013 			   than any item within it that isn't being found */
2014 			if( cryptStatusOK( status ) )
2015 				status = cryptAddPublicKey( cryptKeyset, cryptEncryptCert );
2016 			if( cryptStatusError( status ) )
2017 				return( extErrorExit( cryptKeyset, "cryptAddPublicKey()",
2018 									  status, __LINE__ ) );
2019 
2020 			/* The double-certificate keyset is set up, remember this for
2021 			   later tests */
2022 			doubleCertOK = TRUE;
2023 			}
2024 		cryptKeysetClose( cryptKeyset );
2025 		}
2026 
2027 	/* Clean up */
2028 	cryptDestroyContext( cryptSigContext );
2029 	cryptDestroyContext( cryptEncryptContext );
2030 	cryptDestroyCert( cryptSigCert );
2031 	cryptDestroyCert( cryptEncryptCert );
2032 
2033 	/* Try and read the keys+certs back */
2034 	status = getPrivateKey( &cryptSigContext, DUAL_PRIVKEY_FILE,
2035 							DUAL_SIGNKEY_LABEL, TEST_PRIVKEY_PASSWORD );
2036 	cryptDestroyContext( cryptSigContext );
2037 	if( cryptStatusOK( status ) )
2038 		{
2039 		status = getPrivateKey( &cryptEncryptContext, DUAL_PRIVKEY_FILE,
2040 								DUAL_ENCRYPTKEY_LABEL, TEST_PRIVKEY_PASSWORD );
2041 		cryptDestroyContext( cryptEncryptContext );
2042 		}
2043 	if( cryptStatusError( status ) )
2044 		{
2045 		printExtError( cryptKeyset, "cryptGetPrivateKey()", status,
2046 					   __LINE__ );
2047 		return( FALSE );
2048 		}
2049 
2050 	puts( "Separate signature+encryption certificate write to key file "
2051 		  "succeeded.\n" );
2052 	return( TRUE );
2053 	}
2054 
2055 /* Write a key and two certs of different validity periods to a file */
2056 
2057 #ifndef _WIN32_WCE	/* Windows CE doesn't support ANSI C time functions */
2058 
testRenewedCertFile(void)2059 int testRenewedCertFile( void )
2060 	{
2061 	CRYPT_KEYSET cryptKeyset;
2062 	CRYPT_CERTIFICATE cryptOldCert, cryptNewCert;
2063 	CRYPT_CONTEXT cryptCAKey, cryptContext;
2064 	time_t writtenValidTo = 0 /* Dummy */, readValidTo;
2065 	int dummy, status;
2066 
2067 	puts( "Testing renewed certificate write to key file..." );
2068 
2069 	/* Get the CA's key and the key to certify */
2070 	status = getPrivateKey( &cryptCAKey, CA_PRIVKEY_FILE,
2071 							CA_PRIVKEY_LABEL, TEST_PRIVKEY_PASSWORD );
2072 	if( cryptStatusError( status ) )
2073 		{
2074 		printf( "CA private key read failed with error code %d, line %d.\n",
2075 				status, __LINE__ );
2076 		return( FALSE );
2077 		}
2078 	if( !loadRSAContexts( CRYPT_UNUSED, NULL, &cryptContext ) )
2079 		return( FALSE );
2080 
2081 	/* Create the certs containing the keys */
2082 	status = cryptCreateCert( &cryptOldCert, CRYPT_UNUSED,
2083 							  CRYPT_CERTTYPE_CERTIFICATE );
2084 	if( cryptStatusOK( status ) )
2085 		status = cryptSetAttribute( cryptOldCert,
2086 					CRYPT_CERTINFO_SUBJECTPUBLICKEYINFO, cryptContext );
2087 	if( cryptStatusOK( status ) && \
2088 		!addCertFields( cryptOldCert, certRequestData, __LINE__ ) )
2089 		return( FALSE );
2090 	if( cryptStatusOK( status ) )
2091 		{
2092 		time_t validity = time( NULL );
2093 
2094 		/* Valid for one month ending tomorrow (we can't make it already-
2095 		   expired or cryptlib will complain) */
2096 		validity += 86400;
2097 		cryptSetAttributeString( cryptOldCert,
2098 					CRYPT_CERTINFO_VALIDTO, &validity, sizeof( time_t ) );
2099 		validity -= ( 86400 * 31 );
2100 		status = cryptSetAttributeString( cryptOldCert,
2101 					CRYPT_CERTINFO_VALIDFROM, &validity, sizeof( time_t ) );
2102 		}
2103 	if( cryptStatusOK( status ) )
2104 		status = cryptSignCert( cryptOldCert, cryptCAKey );
2105 	if( cryptStatusError( status ) )
2106 		{
2107 		printf( "Signature certificate creation failed with error code %d, "
2108 				"line %d.\n", status, __LINE__ );
2109 		printErrorAttributeInfo( cryptOldCert );
2110 		return( FALSE );
2111 		}
2112 	status = cryptCreateCert( &cryptNewCert, CRYPT_UNUSED,
2113 							  CRYPT_CERTTYPE_CERTIFICATE );
2114 	if( cryptStatusOK( status ) )
2115 		status = cryptSetAttribute( cryptNewCert,
2116 					CRYPT_CERTINFO_SUBJECTPUBLICKEYINFO, cryptContext );
2117 	if( cryptStatusOK( status ) && \
2118 		!addCertFields( cryptNewCert, certRequestData, __LINE__ ) )
2119 		return( FALSE );
2120 	if( cryptStatusOK( status ) )
2121 		{
2122 		time_t validity = time( NULL );
2123 
2124 		/* Valid for one month starting yesterday (it's actually valid for
2125 		   one month + one day to sidestep the one-month sanity check in the
2126 		   private key read code that warns of about-to-expire keys) */
2127 		validity -= 86400;
2128 		cryptSetAttributeString( cryptNewCert,
2129 					CRYPT_CERTINFO_VALIDFROM, &validity, sizeof( time_t ) );
2130 		validity += ( 86400 * 32 );
2131 		status = cryptSetAttributeString( cryptNewCert,
2132 					CRYPT_CERTINFO_VALIDTO, &validity, sizeof( time_t ) );
2133 		writtenValidTo = validity;
2134 		}
2135 	if( cryptStatusOK( status ) )
2136 		status = cryptSignCert( cryptNewCert, cryptCAKey );
2137 	if( cryptStatusError( status ) )
2138 		{
2139 		printf( "Encryption certificate creation failed with error code %d, "
2140 				"line %d.\n", status, __LINE__ );
2141 		printErrorAttributeInfo( cryptNewCert );
2142 		return( FALSE );
2143 		}
2144 	cryptDestroyContext( cryptCAKey );
2145 
2146 	/* First, open the keyset, write the key and certificates (using an
2147 	   in-memory update), and close it.  This tests the ability to use
2148 	   information cached in memory to handle the update */
2149 	status = cryptKeysetOpen( &cryptKeyset, CRYPT_UNUSED, CRYPT_KEYSET_FILE,
2150 							  RENEW_PRIVKEY_FILE, CRYPT_KEYOPT_CREATE );
2151 	if( cryptStatusError( status ) )
2152 		{
2153 		printf( "cryptKeysetOpen() failed with error code %d, line %d.\n",
2154 				status, __LINE__ );
2155 		return( FALSE );
2156 		}
2157 	status = cryptAddPrivateKey( cryptKeyset, cryptContext,
2158 								 TEST_PRIVKEY_PASSWORD );
2159 	if( cryptStatusError( status ) )
2160 		{
2161 		printExtError( cryptKeyset, "cryptAddPrivateKey()", status,
2162 					   __LINE__ );
2163 		return( FALSE );
2164 		}
2165 	status = cryptAddPublicKey( cryptKeyset, cryptOldCert );
2166 	if( cryptStatusOK( status ) )
2167 		status = cryptAddPublicKey( cryptKeyset, cryptNewCert );
2168 	if( cryptStatusError( status ) )
2169 		{
2170 		printExtError( cryptKeyset,
2171 					   "cryptAddPublicKey() (in-memory update)",
2172 					   status, __LINE__ );
2173 		return( FALSE );
2174 		}
2175 	status = cryptKeysetClose( cryptKeyset );
2176 	if( cryptStatusError( status ) )
2177 		{
2178 		printf( "cryptKeysetClose() failed with error code %d, line %d.\n",
2179 				status, __LINE__ );
2180 		return( FALSE );
2181 		}
2182 
2183 	/* Then try again, but this time perform an on-disk update, closing the
2184 	   keyset between the first and second update.  This tests the ability
2185 	   to recover the information needed to handle the update from data in
2186 	   the keyset */
2187 	status = cryptKeysetOpen( &cryptKeyset, CRYPT_UNUSED, CRYPT_KEYSET_FILE,
2188 							  RENEW_PRIVKEY_FILE, CRYPT_KEYOPT_CREATE );
2189 	if( cryptStatusOK( status ) )
2190 		status = cryptAddPrivateKey( cryptKeyset, cryptContext,
2191 									 TEST_PRIVKEY_PASSWORD );
2192 	if( cryptStatusOK( status ) )
2193 		status = cryptAddPublicKey( cryptKeyset, cryptOldCert );
2194 	if( cryptStatusOK( status ) )
2195 		status = cryptKeysetClose( cryptKeyset );
2196 	if( cryptStatusError( status ) )
2197 		{
2198 		printf( "Keyset creation in preparation for on-disk update failed "
2199 				"with error code %d, line %d.\n", status, __LINE__ );
2200 		return( FALSE );
2201 		}
2202 	status = cryptKeysetOpen( &cryptKeyset, CRYPT_UNUSED, CRYPT_KEYSET_FILE,
2203 							  RENEW_PRIVKEY_FILE, CRYPT_KEYOPT_NONE );
2204 	if( cryptStatusOK( status ) )
2205 		status = cryptAddPublicKey( cryptKeyset, cryptNewCert );
2206 	if( cryptStatusError( status ) )
2207 		{
2208 		printExtError( cryptKeyset, "cryptAddPublicKey() (on-disk update)",
2209 					   status, __LINE__ );
2210 		return( FALSE );
2211 		}
2212 	status = cryptKeysetClose( cryptKeyset );
2213 	if( cryptStatusError( status ) )
2214 		{
2215 		printf( "cryptKeysetClose() failed with error code %d, line %d.\n",
2216 				status, __LINE__ );
2217 		return( FALSE );
2218 		}
2219 
2220 	/* Clean up */
2221 	cryptDestroyContext( cryptContext );
2222 	cryptDestroyCert( cryptOldCert );
2223 	cryptDestroyCert( cryptNewCert );
2224 
2225 	/* Try and read the (newest) key+certificate back */
2226 	status = getPrivateKey( &cryptContext, RENEW_PRIVKEY_FILE,
2227 							RSA_PRIVKEY_LABEL, TEST_PRIVKEY_PASSWORD );
2228 	if( cryptStatusError( status ) )
2229 		{
2230 		printf( "Private key read failed with error code %d, line %d.\n",
2231 				status, __LINE__ );
2232 		return( FALSE );
2233 		}
2234 	status = cryptGetAttributeString( cryptContext,
2235 					CRYPT_CERTINFO_VALIDTO, &readValidTo, &dummy );
2236 	if( cryptStatusError( status ) )
2237 		return( attrErrorExit( cryptContext, "cryptGetAttributeString",
2238 							   status, __LINE__ ) );
2239 	if( writtenValidTo != readValidTo )
2240 		{
2241 		const int diff = ( int ) ( readValidTo - writtenValidTo );
2242 		const char *units = ( diff % 60 ) ? "seconds" : "minutes";
2243 
2244 		printf( "Returned certificate != latest valid certificate, diff.= "
2245 				"%d %s, line %d.\n", ( diff % 60 ) ? diff : diff / 60,
2246 				units, __LINE__ );
2247 		if( diff == 3600 || diff ==  -3600 )
2248 			{
2249 			/* See the comment on DST issues in testcert.c */
2250 			puts( "  (This is probably due to a difference between DST at "
2251 				  "certificate creation and DST\n   now, and isn't a "
2252 				  "serious problem)." );
2253 			}
2254 		else
2255 			return( FALSE );
2256 		}
2257 	cryptDestroyContext( cryptContext );
2258 
2259 	puts( "Renewed certificate write to key file succeeded.\n" );
2260 	return( TRUE );
2261 	}
2262 
2263 #else
2264 
testRenewedCertFile(void)2265 int testRenewedCertFile( void )
2266 	{
2267 	/* Since the renewal is time-based, we can't easily test this under
2268 	   WinCE */
2269 	return( TRUE );
2270 	}
2271 #endif /* WinCE */
2272 
2273 /* Test reading various non-cryptlib PKCS #15 files */
2274 
testReadMiscFile(void)2275 int testReadMiscFile( void )
2276 	{
2277 	CRYPT_KEYSET cryptKeyset;
2278 	BYTE filenameBuffer[ FILENAME_BUFFER_SIZE ];
2279 #ifdef UNICODE_STRINGS
2280 	wchar_t wcBuffer[ FILENAME_BUFFER_SIZE ];
2281 #endif /* UNICODE_STRINGS */
2282 	void *fileNamePtr = filenameBuffer;
2283 	int status;
2284 
2285 	puts( "Testing miscellaneous key file read..." );
2286 
2287 	filenameFromTemplate( filenameBuffer, MISC_PRIVKEY_FILE_TEMPLATE, 1 );
2288 #ifdef UNICODE_STRINGS
2289 	mbstowcs( wcBuffer, filenameBuffer, strlen( filenameBuffer ) + 1 );
2290 	fileNamePtr = wcBuffer;
2291 #endif /* UNICODE_STRINGS */
2292 	status = cryptKeysetOpen( &cryptKeyset, CRYPT_UNUSED, CRYPT_KEYSET_FILE,
2293 							  fileNamePtr, CRYPT_KEYOPT_READONLY );
2294 	if( cryptStatusError( status ) )
2295 		{
2296 		printf( "Couldn't open/scan keyset, status %d, line %d.\n",
2297 				status, __LINE__ );
2298 		return( FALSE );
2299 		}
2300 #if 0
2301 	status = cryptGetPrivateKey( cryptKeyset, &cryptContext,
2302 								 CRYPT_KEYID_NAME,
2303 								 TEXT( "56303156793b318327b25a84808f2cb311c55b0b" ),
2304 								 TEXT( "PASSWORD" ) );
2305 	if( cryptStatusError( status ) )
2306 		{
2307 		printExtError( cryptKeyset, "cryptGetPrivateKey()", status,
2308 					   __LINE__ );
2309 		return( FALSE );
2310 		}
2311 #endif /* 0 */
2312 	cryptKeysetClose( cryptKeyset );
2313 
2314 	puts( "Miscellaneous key file succeeded.\n" );
2315 	return( TRUE );
2316 	}
2317 
2318 /* Generic test routines used for debugging */
2319 
xxxPrivKeyRead(const char * fileName,const char * keyName,const char * password)2320 void xxxPrivKeyRead( const char *fileName, const char *keyName,
2321 					 const char *password )
2322 	{
2323 	CRYPT_KEYSET cryptKeyset;
2324 	CRYPT_CONTEXT cryptContext;
2325 	int status;
2326 
2327 	/* Open the file keyset */
2328 	status = cryptKeysetOpen( &cryptKeyset, CRYPT_UNUSED, CRYPT_KEYSET_FILE,
2329 							  fileName, CRYPT_KEYOPT_READONLY );
2330 	assert( cryptStatusOK( status ) );
2331 
2332 	/* Read the key from the file */
2333 	if( password == NULL )
2334 		{
2335 		status = cryptGetPublicKey( cryptKeyset, &cryptContext,
2336 									CRYPT_KEYID_NAME, keyName );
2337 		}
2338 	else
2339 		{
2340 		status = cryptGetPrivateKey( cryptKeyset, &cryptContext,
2341 									 CRYPT_KEYID_NAME, keyName, password );
2342 		}
2343 	assert( cryptStatusOK( status ) );
2344 
2345 	cryptKeysetClose( cryptKeyset );
2346 	}
2347 
xxxPubKeyRead(const char * fileName,const char * keyName)2348 void xxxPubKeyRead( const char *fileName, const char *keyName )
2349 	{
2350 	xxxPrivKeyRead( fileName, keyName, NULL );
2351 	}
2352 
2353 /****************************************************************************
2354 *																			*
2355 *								Test Key Generation							*
2356 *																			*
2357 ****************************************************************************/
2358 
2359 #if 1
2360 
2361 /* Generate test keys for CA and security protocol use.  This enables
2362    various special-case extensions such as extKeyUsages or protocol-specific
2363    AIA entries, as well as using a validity period of 5 years instead of the
2364    usual 1 year to avoid problems when users run the self-test on very old
2365    copies of the code.  The keys generated into /test/keys are:
2366 
2367 	File define			File			Description
2368 	-----------			----			-----------
2369 	CA_PRIVKEY_FILE		ca.p15			Root CA key.
2370 		CMP_CA_FILE		cmp_ca1.der		Written as side-effect of the above.
2371 	ICA_PRIVKEY_FILE	ca_int.p15		Intermediate CA key + root CA cert.
2372 	SCEPCA_PRIVKEY_FILE	ca_scep.p15		SCEP CA key + root CA cert, SCEP CA
2373 										keyUsage allows encryption + signing.
2374 		SCEP_CA_FILE	scep_ca1.der	Written as side-effect of the above.
2375 	SERVER_PRIVKEY_FILE	server1.p15		SSL server key + root CA cert, server
2376 										cert has CN = localhost, OCSP AIA.
2377 	SERVER_PRIVKEY_FILE	server2.p15		As server2.p15 but with a different
2378 										key, used to check that use of the
2379 										wrong key is detected.
2380 	SSH_PRIVKEY_FILE	ssh1.p15		Raw SSHv1 RSA key.
2381 	SSH_PRIVKEY_FILE	ssh2.p15		Raw SSHv2 DSA key.
2382 	SSH_PRIVKEY_FILE	ssh3.p15		Raw SSHv2 ECDSA key.
2383 	TSA_PRIVKEY_FILE	tsa.p15			TSA server key + root CA cert, TSA
2384 										cert has TSP extKeyUsage.
2385 	USER_PRIVKEY_FILE	user1.p15		User key + root CA cert, user cert
2386 										has email address.
2387 	USER_PRIVKEY_FILE	user2.p15		(Via template): User key using SHA256
2388 										+ root CA cert, user cert has email
2389 										address.  Used to test auto-upgrade
2390 										of enveloping algos to SHA256.
2391 										Note that since 3.4.3 the default
2392 										algorithm is now SHA256 anyway so
2393 										this test is a no-op, but the
2394 										functionality is left in place to
2395 										test future upgrades to new hash
2396 										algorithms.
2397 	USER_PRIVKEY_FILE	user3.p15		(Via template): User key +
2398 										intermediate CA cert + root CA cert.
2399 
2400 										(OCSP_CA_FILE is written by the
2401 										testCertManagement() code).
2402 
2403    Other keys written by the self-test process are:
2404 
2405 	CMP_PRIVKEY_FILE	cmp*.p15		Created during the CMP self-test.
2406 	DUAL_PRIVKEY_FILE	dual.p15		For test of signature + encryption
2407 										cert in same file in
2408 										testDoubleCertFile().
2409 	PNPCA_PRIVKEY_FILE	pnp_ca.p15		Created during the PnP PKI self-test,
2410 	PNP_PRIVKEY_FILE	pnp_user.p15	_ca is for a CA cert request, _user
2411 										is for a user cert request.
2412 	RENEW_PRIVKEY_FILE	renewed.p15		For test of update of older cert with
2413 										newer one in testRenewedCertFile().
2414 	TEST_PRIVKEY_FILE	test.p15		Generic test key file */
2415 
2416 static const CERT_DATA FAR_BSS serverCertRequestData[] = {
2417 	/* Identification information */
2418 	{ CRYPT_CERTINFO_COUNTRYNAME, IS_STRING, 0, TEXT( "NZ" ) },
2419 	{ CRYPT_CERTINFO_ORGANIZATIONNAME, IS_STRING, 0, TEXT( "Dave's Wetaburgers" ) },
2420 	{ CRYPT_CERTINFO_ORGANIZATIONALUNITNAME, IS_STRING, 0, TEXT( "Server cert" ) },
2421 	{ CRYPT_CERTINFO_COMMONNAME, IS_STRING, 0, TEXT( "localhost" ) },
2422 
2423 	/* Add an OCSP AIA entry */
2424 	{ CRYPT_ATTRIBUTE_CURRENT, IS_NUMERIC, CRYPT_CERTINFO_AUTHORITYINFO_OCSP },
2425 	{ CRYPT_CERTINFO_UNIFORMRESOURCEIDENTIFIER, IS_STRING, 0, TEXT( "http://localhost" ) },
2426 	{ CRYPT_ATTRIBUTE_NONE, 0, 0, NULL }
2427 	};
2428 
2429 static const CERT_DATA FAR_BSS iCACertRequestData[] = {
2430 	/* Identification information */
2431 	{ CRYPT_CERTINFO_COUNTRYNAME, IS_STRING, 0, TEXT( "NZ" ) },
2432 	{ CRYPT_CERTINFO_ORGANIZATIONNAME, IS_STRING, 0, TEXT( "Dave's Wetaburgers" ) },
2433 	{ CRYPT_CERTINFO_ORGANIZATIONALUNITNAME, IS_STRING, 0, TEXT( "Intermediate CA cert" ) },
2434 	{ CRYPT_CERTINFO_COMMONNAME, IS_STRING, 0, TEXT( "Dave's Spare CA" ) },
2435 
2436 	/* Set the CA key usage extensions */
2437 	{ CRYPT_CERTINFO_CA, IS_NUMERIC, TRUE },
2438 	{ CRYPT_CERTINFO_KEYUSAGE, IS_NUMERIC, CRYPT_KEYUSAGE_KEYCERTSIGN },
2439 	{ CRYPT_ATTRIBUTE_NONE, 0, 0, NULL }
2440 	};
2441 
2442 static const CERT_DATA FAR_BSS scepCACertRequestData[] = {
2443 	/* Identification information */
2444 	{ CRYPT_CERTINFO_COUNTRYNAME, IS_STRING, 0, TEXT( "NZ" ) },
2445 	{ CRYPT_CERTINFO_ORGANIZATIONNAME, IS_STRING, 0, TEXT( "Dave's Wetaburgers" ) },
2446 	{ CRYPT_CERTINFO_ORGANIZATIONALUNITNAME, IS_STRING, 0, TEXT( "SCEP CA cert" ) },
2447 	{ CRYPT_CERTINFO_COMMONNAME, IS_STRING, 0, TEXT( "Dave's SCEP CA" ) },
2448 
2449 	/* Set the CA as well as generic sign+encrypt key usage extensions */
2450 	{ CRYPT_CERTINFO_CA, IS_NUMERIC, TRUE },
2451 	{ CRYPT_CERTINFO_KEYUSAGE, IS_NUMERIC, CRYPT_KEYUSAGE_KEYCERTSIGN | \
2452 										   CRYPT_KEYUSAGE_DIGITALSIGNATURE | \
2453 										   CRYPT_KEYUSAGE_KEYENCIPHERMENT },
2454 	{ CRYPT_ATTRIBUTE_NONE, 0, 0, NULL }
2455 	};
2456 
2457 static const CERT_DATA FAR_BSS tsaCertRequestData[] = {
2458 	/* Identification information */
2459 	{ CRYPT_CERTINFO_COUNTRYNAME, IS_STRING, 0, TEXT( "NZ" ) },
2460 	{ CRYPT_CERTINFO_ORGANIZATIONNAME, IS_STRING, 0, TEXT( "Dave's Wetaburgers" ) },
2461 	{ CRYPT_CERTINFO_ORGANIZATIONALUNITNAME, IS_STRING, 0, TEXT( "TSA Cert" ) },
2462 	{ CRYPT_CERTINFO_COMMONNAME, IS_STRING, 0, TEXT( "Dave's TSA" ) },
2463 
2464 	/* Set the TSP extended key usage */
2465 	{ CRYPT_CERTINFO_KEYUSAGE, IS_NUMERIC, CRYPT_KEYUSAGE_DIGITALSIGNATURE },
2466 	{ CRYPT_CERTINFO_EXTKEY_TIMESTAMPING, IS_NUMERIC, CRYPT_UNUSED },
2467 	{ CRYPT_ATTRIBUTE_NONE, 0, 0, NULL }
2468 	};
2469 
2470 static const CERT_DATA FAR_BSS userCertRequestData[] = {
2471 	/* Identification information */
2472 	{ CRYPT_CERTINFO_COUNTRYNAME, IS_STRING, 0, TEXT( "NZ" ) },
2473 	{ CRYPT_CERTINFO_ORGANIZATIONNAME, IS_STRING, 0, TEXT( "Dave's Wetaburgers" ) },
2474 	{ CRYPT_CERTINFO_ORGANIZATIONALUNITNAME, IS_STRING, 0, TEXT( "Procurement" ) },
2475 	{ CRYPT_CERTINFO_COMMONNAME, IS_STRING, 0, TEXT( "Dave Smith" ) },
2476 	{ CRYPT_CERTINFO_EMAIL, IS_STRING, 0, TEXT( "dave@wetaburgers.com" ) },
2477 	{ CRYPT_ATTRIBUTE_CURRENT, IS_NUMERIC, CRYPT_CERTINFO_SUBJECTNAME },	/* Re-select subject DN */
2478 
2479 	{ CRYPT_ATTRIBUTE_NONE, 0, 0, NULL }
2480 	};
2481 
2482 /* Create a standalone private key + certificate */
2483 
createCAKeyFile(void)2484 static int createCAKeyFile( void )
2485 	{
2486 	CRYPT_KEYSET cryptKeyset;
2487 	CRYPT_CERTIFICATE cryptCert;
2488 	CRYPT_CONTEXT cryptContext;
2489 	FILE *filePtr;
2490 	BYTE certBuffer[ BUFFER_SIZE ];
2491 	char filenameBuffer[ FILENAME_BUFFER_SIZE ];
2492 #ifndef _WIN32_WCE	/* Windows CE doesn't support ANSI C time functions */
2493 	const time_t validity = time( NULL ) + ( 86400L * 365 * 3 );
2494 #endif /* _WIN32_WCE */
2495 	int length, status;
2496 
2497 	/* Create a self-signed CA certificate */
2498 	status = cryptCreateContext( &cryptContext, CRYPT_UNUSED, CRYPT_ALGO_RSA );
2499 	if( cryptStatusOK( status ) )
2500 		status = cryptSetAttributeString( cryptContext, CRYPT_CTXINFO_LABEL,
2501 										  CA_PRIVKEY_LABEL,
2502 										  paramStrlen( CA_PRIVKEY_LABEL ) );
2503 	if( cryptStatusOK( status ) )
2504 		status = cryptGenerateKey( cryptContext );
2505 	if( cryptStatusError( status ) )
2506 		return( status );
2507 	status = cryptCreateCert( &cryptCert, CRYPT_UNUSED,
2508 							  CRYPT_CERTTYPE_CERTIFICATE );
2509 	if( cryptStatusOK( status ) )
2510 		status = cryptSetAttribute( cryptCert,
2511 						CRYPT_CERTINFO_SUBJECTPUBLICKEYINFO, cryptContext );
2512 	if( cryptStatusError( status ) )
2513 		return( status );
2514 	if( !addCertFields( cryptCert, cACertData, __LINE__ ) )
2515 		return( CRYPT_ERROR_FAILED );
2516 
2517 #ifndef _WIN32_WCE	/* Windows CE doesn't support ANSI C time functions */
2518 	/* Make it valid for 5 years instead of 1 to avoid problems when users
2519 	   run the self-test with very old copies of the code */
2520 	cryptSetAttributeString( cryptCert,
2521 					CRYPT_CERTINFO_VALIDTO, &validity, sizeof( time_t ) );
2522 	if( cryptStatusOK( status ) )
2523 		status = cryptSignCert( cryptCert, cryptContext );
2524 	if( cryptStatusError( status ) )
2525 		return( status );
2526 #endif /* _WIN32_WCE */
2527 
2528 	/* Open the keyset, update it with the certificate, and close it */
2529 	status = cryptKeysetOpen( &cryptKeyset, CRYPT_UNUSED, CRYPT_KEYSET_FILE,
2530 							  CA_PRIVKEY_FILE, CRYPT_KEYOPT_CREATE );
2531 	if( cryptStatusError( status ) )
2532 		return( status );
2533 	status = cryptAddPrivateKey( cryptKeyset, cryptContext,
2534 								 TEST_PRIVKEY_PASSWORD );
2535 	if( cryptStatusOK( status ) )
2536 		status = cryptAddPublicKey( cryptKeyset, cryptCert );
2537 	if( cryptStatusError( status ) )
2538 		return( status );
2539 
2540 	/* Save the certificate to disk for use in request/response protocols */
2541 	status = cryptExportCert( certBuffer, BUFFER_SIZE, &length,
2542 							  CRYPT_CERTFORMAT_CERTIFICATE, cryptCert );
2543 	if( cryptStatusError( status ) )
2544 		return( status );
2545 	filenameFromTemplate( filenameBuffer, CMP_CA_FILE_TEMPLATE, 1 );
2546 	if( ( filePtr = fopen( filenameBuffer, "wb" ) ) != NULL )
2547 		{
2548 		int count;
2549 
2550 		count = fwrite( certBuffer, 1, length, filePtr );
2551 		fclose( filePtr );
2552 		if( count < length )
2553 			{
2554 			remove( filenameBuffer );
2555 			puts( "Warning: Couldn't save CA certificate to disk, "
2556 				  "this will cause later\n         tests to fail.  "
2557 				  "Press a key to continue." );
2558 			getchar();
2559 			}
2560 		}
2561 
2562 	cryptDestroyCert( cryptCert );
2563 	cryptDestroyContext( cryptContext );
2564 	cryptKeysetClose( cryptKeyset );
2565 
2566 	return( CRYPT_OK );
2567 	}
2568 
2569 /* Create a raw SSH private key */
2570 
createSSHKeyFile(const int keyNo)2571 static int createSSHKeyFile( const int keyNo )
2572 	{
2573 	CRYPT_KEYSET cryptKeyset;
2574 	CRYPT_CONTEXT cryptContext;
2575 	BYTE filenameBuffer[ FILENAME_BUFFER_SIZE ];
2576 	int status;
2577 
2578 	/* Create a private key */
2579 	status = cryptCreateContext( &cryptContext, CRYPT_UNUSED,
2580 								 ( keyNo == 1 ) ? CRYPT_ALGO_RSA : \
2581 								 ( keyNo == 2 ) ? CRYPT_ALGO_DSA : \
2582 												  CRYPT_ALGO_ECDSA );
2583 	if( cryptStatusOK( status ) )
2584 		status = cryptSetAttributeString( cryptContext, CRYPT_CTXINFO_LABEL,
2585 										  USER_PRIVKEY_LABEL,
2586 										  paramStrlen( USER_PRIVKEY_LABEL ) );
2587 	if( cryptStatusOK( status ) )
2588 		status = cryptGenerateKey( cryptContext );
2589 	if( cryptStatusError( status ) )
2590 		return( status );
2591 
2592 	/* Open the keyset, add the key, and close it */
2593 	filenameFromTemplate( filenameBuffer, SSH_PRIVKEY_FILE_TEMPLATE, keyNo );
2594 	status = cryptKeysetOpen( &cryptKeyset, CRYPT_UNUSED, CRYPT_KEYSET_FILE,
2595 							  filenameBuffer, CRYPT_KEYOPT_CREATE );
2596 	if( cryptStatusError( status ) )
2597 		return( status );
2598 	status = cryptAddPrivateKey( cryptKeyset, cryptContext,
2599 								 TEST_PRIVKEY_PASSWORD );
2600 	if( cryptStatusError( status ) )
2601 		return( status );
2602 	cryptDestroyContext( cryptContext );
2603 	cryptKeysetClose( cryptKeyset );
2604 
2605 	return( CRYPT_OK );
2606 	}
2607 
2608 /* Create a pseudo-certificate file, used to test embedded versions of
2609    cryptlib running an SSL/TLS server when it's built with
2610    CONFIG_NO_CERTIFICATES */
2611 
createPseudoCertificateFile(void)2612 static int createPseudoCertificateFile( void )
2613 	{
2614 	CRYPT_CONTEXT cryptContext, cryptCAKey;
2615 	CRYPT_CERTIFICATE cryptCertChain;
2616 	FILE *filePtr;
2617 	BYTE certBuffer[ BUFFER_SIZE ], *certBufPtr = certBuffer;
2618 	char filenameBuffer[ FILENAME_BUFFER_SIZE ];
2619 	int certBufSize = BUFFER_SIZE, status;
2620 
2621 	/* Load a fixed RSA private key */
2622 	if( !loadRSAContexts( CRYPT_UNUSED, NULL, &cryptContext ) )
2623 		return( CRYPT_ERROR_NOTAVAIL );
2624 
2625 	/* Get the CA's private key */
2626 	status = getPrivateKey( &cryptCAKey, ICA_PRIVKEY_FILE,
2627 							USER_PRIVKEY_LABEL, TEST_PRIVKEY_PASSWORD );
2628 	if( cryptStatusError( status ) )
2629 		return( status );
2630 
2631 	/* Create the certificate chain for the SSL server key */
2632 	status = cryptCreateCert( &cryptCertChain, CRYPT_UNUSED,
2633 							  CRYPT_CERTTYPE_CERTCHAIN );
2634 	if( cryptStatusOK( status ) )
2635 		status = cryptSetAttribute( cryptCertChain,
2636 							CRYPT_CERTINFO_SUBJECTPUBLICKEYINFO, cryptContext );
2637 	cryptDestroyContext( cryptContext );
2638 	if( cryptStatusOK( status ) && \
2639 		!addCertFields( cryptCertChain, serverCertRequestData, __LINE__ ) )
2640 		return( CRYPT_ERROR_FAILED );
2641 	if( cryptStatusOK( status ) )
2642 		status = cryptSignCert( cryptCertChain, cryptCAKey );
2643 	cryptDestroyContext( cryptCAKey );
2644 	if( cryptStatusError( status ) )
2645 		return( status );
2646 
2647 	/* Export the chain as an SSL certificate chain.  We can't use
2648 	   CRYPT_IFORMAT_SSL for this since it's is a cryptlib-internal format,
2649 	   so we have to manually assemble the SSL chain ourselves */
2650 	status = cryptSetAttribute( cryptCertChain,
2651 								CRYPT_CERTINFO_CURRENT_CERTIFICATE,
2652 								CRYPT_CURSOR_FIRST );
2653 	if( cryptStatusError( status ) )
2654 		return( status );
2655 	do
2656 		{
2657 		int length;
2658 
2659 		/* Export the certificate, leaving room for the 24-bit length at the
2660 		   start */
2661 		status = cryptExportCert( certBufPtr + 3, certBufSize - 3, &length,
2662 								  CRYPT_CERTFORMAT_CERTIFICATE,
2663 								  cryptCertChain );
2664 		if( cryptStatusError( status ) )
2665 			return( status );
2666 
2667 		/* Add in the 24-bit length required by SSL/TLS */
2668 		certBufPtr[ 0 ] = 0;
2669 		certBufPtr[ 1 ] = ( length >> 8 );
2670 		certBufPtr[ 2 ] = ( length & 0xFF );
2671 		certBufPtr += 3 + length;
2672 		certBufSize -= 3 + length;
2673 		}
2674 	while( cryptSetAttribute( cryptCertChain,
2675 							  CRYPT_CERTINFO_CURRENT_CERTIFICATE,
2676 							  CRYPT_CURSOR_NEXT ) == CRYPT_OK );
2677 	cryptDestroyCert( cryptCertChain );
2678 
2679 	/* Write the SSL-format certificate chain to disk */
2680 	filenameFromTemplate( filenameBuffer, PSEUDOCERT_FILE_TEMPLATE, 1 );
2681 	if( ( filePtr = fopen( filenameBuffer, "wb" ) ) != NULL )
2682 		{
2683 		const int length = BUFFER_SIZE - certBufSize;
2684 		int count;
2685 
2686 		count = fwrite( certBuffer, 1, length, filePtr );
2687 		fclose( filePtr );
2688 		if( count < length )
2689 			{
2690 			remove( filenameBuffer );
2691 			puts( "Warning: Couldn't save SSL chain to disk, "
2692 				  "this will cause later\n         tests to fail.  "
2693 				  "Press a key to continue." );
2694 			getchar();
2695 			}
2696 		}
2697 
2698 	return( CRYPT_OK );
2699 	}
2700 
2701 /* Build a certificate chain without the root certificate.  This gets quite
2702    complicated to do, we can't just delete the root with:
2703 
2704 	cryptSetAttribute( certificate, CRYPT_CERTINFO_CURRENT_CERTIFICATE,
2705 					   CRYPT_CURSOR_FIRST );
2706 	cryptDeleteAttribute( certificate, CRYPT_CERTINFO_CURRENT_CERTIFICATE );
2707 
2708    because the chain is locked against updates, and we can't use a
2709    temporary keyset file to assemble the chain via:
2710 
2711 	cryptKeysetOpen( &cryptKeyset, CRYPT_UNUSED, CRYPT_KEYSET_FILE,
2712 					 TEST_PRIVKEY_FILE, CRYPT_KEYOPT_CREATE );
2713 	cryptSetAttribute( certChain, CRYPT_CERTINFO_CURRENT_CERTIFICATE,
2714 					   CRYPT_CURSOR_FIRST );
2715 	cryptExportCert( buffer, BUFFER_SIZE, &certSize,
2716 					 CRYPT_CERTFORMAT_CERTIFICATE, certChain );
2717 	cryptImportCert( buffer, certSize, CRYPT_UNUSED, &certificate );
2718 	cryptSetAttribute( certificate, CRYPT_CERTINFO_TRUSTED_IMPLICIT, TRUE );
2719 	cryptAddPublicKey( cryptKeyset, certificate );
2720 	cryptSetAttribute( certChain, CRYPT_CERTINFO_CURRENT_CERTIFICATE,
2721 					   CRYPT_CURSOR_NEXT );
2722 	cryptExportCert( buffer, BUFFER_SIZE, &certSize,
2723 					 CRYPT_CERTFORMAT_CERTIFICATE, certChain );
2724 	cryptImportCert( buffer, certSize, CRYPT_UNUSED, &certificate );
2725 	cryptSetAttribute( certificate, CRYPT_CERTINFO_TRUSTED_IMPLICIT, TRUE );
2726 	cryptAddPublicKey( cryptKeyset, certificate );
2727 	cryptKeysetClose( cryptKeyset );
2728 	cryptDestroyCert( certificate );
2729 
2730    because the leaf certificate is an EE certificate and therefore can't be
2731    made explicitly trusted.  Because of this we have to create a pesudo-
2732    encoding of a certificate chain by copying a fixed-size indefinite-length-
2733    encoding header into a buffer:
2734 
2735 	   0 NDEF: SEQUENCE {
2736 	   2    9:   OBJECT IDENTIFIER signedData (1 2 840 113549 1 7 2)
2737 	  13 NDEF:   [0] {
2738 	  15 NDEF:     SEQUENCE {
2739 	  17    1:       INTEGER 1
2740 	  20   11:       SET {
2741 	  22    9:         SEQUENCE {
2742 	  24    5:           OBJECT IDENTIFIER sha1 (1 3 14 3 2 26)
2743 	  31    0:           NULL
2744 	         :           }
2745 	         :         }
2746 	  33   11:       SEQUENCE {
2747 	  35    9:         OBJECT IDENTIFIER data (1 2 840 113549 1 7 1)
2748 	         :         }
2749 	  46 NDEF:       [0] {
2750 
2751    and then appending the certificates to it, which on import becomes a
2752    canonicalised certificate chain */
2753 
2754 static BYTE certChainHeader[] = { \
2755 	0x30, 0x80, 0x06, 0x09, 0x2A, 0x86, 0x48, 0x86,
2756 	0xF7, 0x0D, 0x01, 0x07, 0x02, 0xA0, 0x80, 0x30,
2757 	0x80, 0x02, 0x01, 0x01, 0x31, 0x0B, 0x30, 0x09,
2758 	0x06, 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A, 0x05,
2759 	0x00, 0x30, 0x0B, 0x06, 0x09, 0x2A, 0x86, 0x48,
2760 	0x86, 0xF7, 0x0D, 0x01, 0x07, 0x01, 0xA0, 0x80
2761 	};
2762 
writeCertChainNoRoot(void)2763 static int writeCertChainNoRoot( void )
2764 	{
2765 	CRYPT_CERTIFICATE certChain;
2766 	FILE *filePtr;
2767 	BYTE buffer[ BUFFER_SIZE ];
2768 	char filenameBuffer[ FILENAME_BUFFER_SIZE ];
2769 	int bufPos, certSize, status;
2770 
2771 	/* Get the complete certificate chain */
2772 	filenameFromTemplate( filenameBuffer, USER_PRIVKEY_FILE_TEMPLATE, 3 );
2773 	status = getPublicKey( &certChain, filenameBuffer, USER_PRIVKEY_LABEL );
2774 	if( cryptStatusError( status ) )
2775 		return( status );
2776 
2777 	/* Export the required individual certificates from the chain and write
2778 	   them into a new pseudo-chain that we can import */
2779 	memcpy( buffer, certChainHeader, 48 );
2780 	bufPos = 48;
2781 	cryptSetAttribute( certChain, CRYPT_CERTINFO_CURRENT_CERTIFICATE,
2782 					   CRYPT_CURSOR_FIRST );
2783 	status = cryptExportCert( buffer + bufPos, BUFFER_SIZE - bufPos,
2784 							  &certSize, CRYPT_CERTFORMAT_CERTIFICATE,
2785 							  certChain );
2786 	if( cryptStatusOK( status ) )
2787 		{
2788 		bufPos += certSize;
2789 		cryptSetAttribute( certChain, CRYPT_CERTINFO_CURRENT_CERTIFICATE,
2790 						   CRYPT_CURSOR_NEXT );
2791 		status = cryptExportCert( buffer + bufPos, BUFFER_SIZE - bufPos,
2792 								  &certSize, CRYPT_CERTFORMAT_CERTIFICATE,
2793 								  certChain );
2794 		}
2795 	if( cryptStatusOK( status ) )
2796 		{
2797 		/* Add the 2-byte EOCs */
2798 		bufPos += certSize;
2799 		memset( buffer + bufPos, 0, 4 * 2 );
2800 		bufPos += 4 * 2;
2801 		}
2802 	cryptDestroyCert( certChain );
2803 	if( cryptStatusError( status ) )
2804 		return( status );
2805 
2806 	/* Import the data as a new certificate chain, re-export it to
2807 	   canonicalise it, and finally write the results to the output file */
2808 	status = cryptImportCert( buffer, bufPos, CRYPT_UNUSED, &certChain );
2809 	if( cryptStatusOK( status ) )
2810 		{
2811 		status = cryptExportCert( buffer, BUFFER_SIZE, &certSize,
2812 								  CRYPT_CERTFORMAT_CERTCHAIN, certChain );
2813 		}
2814 	cryptDestroyCert( certChain );
2815 	if( cryptStatusError( status ) )
2816 		return( status );
2817 	filenameFromTemplate( filenameBuffer, CHAINTEST_FILE_TEMPLATE,
2818 						  CHAINTEST_CHAIN_NOROOT );
2819 	if( ( filePtr = fopen( filenameBuffer, "wb" ) ) != NULL )
2820 		{
2821 		int count;
2822 
2823 		count = fwrite( buffer, 1, certSize, filePtr );
2824 		fclose( filePtr );
2825 		if( count < certSize )
2826 			{
2827 			remove( filenameBuffer );
2828 			puts( "Warning: Couldn't save certificate chain to disk, "
2829 				  "this will cause later\n         tests to fail.  "
2830 				  "Press a key to continue." );
2831 			getchar();
2832 			}
2833 		}
2834 
2835 	return( CRYPT_OK );
2836 	}
2837 
2838 /* Create the cryptlib test keys */
2839 
createTestKeys(void)2840 int createTestKeys( void )
2841 	{
2842 	char filenameBuffer[ FILENAME_BUFFER_SIZE ];
2843 	int status;
2844 
2845 	puts( "Creating custom key files and associated certificate files..." );
2846 
2847 	if( cryptQueryCapability( CRYPT_ALGO_ECDSA, \
2848 							  NULL ) == CRYPT_ERROR_NOTAVAIL )
2849 		{
2850 		puts( "Error: ECDSA must be enabled to create the custom key "
2851 			  "files." );
2852 		return( FALSE );
2853 		}
2854 
2855 	printf( "CA root key + CMP request certificate... " );
2856 	status = createCAKeyFile();
2857 	if( cryptStatusOK( status ) )
2858 		{
2859 		printf( "done.\nSSH RSA server key... " );
2860 		status = createSSHKeyFile( 1 );
2861 		}
2862 	if( cryptStatusOK( status ) )
2863 		{
2864 		printf( "done.\nSSH DSA server key... " );
2865 		status = createSSHKeyFile( 2 );
2866 		}
2867 	if( cryptStatusOK( status ) )
2868 		{
2869 		printf( "done.\nSSH ECC server key... " );
2870 		status = createSSHKeyFile( 3 );
2871 		}
2872 	if( cryptStatusOK( status ) )
2873 		{
2874 		printf( "done.\nSSL/TLS RSA server key... " );
2875 
2876 		filenameFromTemplate( filenameBuffer, SERVER_PRIVKEY_FILE_TEMPLATE, 1 );
2877 		if( !writeFileCertChain( serverCertRequestData, filenameBuffer,
2878 								 NULL, FALSE, FALSE, CRYPT_ALGO_RSA,
2879 								 CRYPT_USE_DEFAULT ) )
2880 			status = CRYPT_ERROR_FAILED;
2881 		}
2882 	if( cryptStatusOK( status ) )
2883 		{
2884 		printf( "done.\nSSL/TLS RSA alternative server key... " );
2885 
2886 		filenameFromTemplate( filenameBuffer, SERVER_PRIVKEY_FILE_TEMPLATE, 2 );
2887 		if( !writeFileCertChain( serverCertRequestData, filenameBuffer,
2888 								 NULL, FALSE, FALSE, CRYPT_ALGO_RSA,
2889 								 CRYPT_USE_DEFAULT ) )
2890 			status = CRYPT_ERROR_FAILED;
2891 		}
2892 	if( cryptStatusOK( status ) )
2893 		{
2894 		printf( "done.\nSSL/TLS ECC P256 server key... " );
2895 
2896 		filenameFromTemplate( filenameBuffer, SERVER_ECPRIVKEY_FILE_TEMPLATE, 256 );
2897 		if( !writeFileCertChain( serverCertRequestData, filenameBuffer,
2898 								 NULL, FALSE, FALSE, CRYPT_ALGO_ECDSA,
2899 								 CRYPT_USE_DEFAULT ) )
2900 			status = CRYPT_ERROR_FAILED;
2901 		}
2902 	if( cryptStatusOK( status ) )
2903 		{
2904 		printf( "done.\nSSL/TLS ECC P384 server key... " );
2905 
2906 		filenameFromTemplate( filenameBuffer, SERVER_ECPRIVKEY_FILE_TEMPLATE, 384 );
2907 		if( !writeFileCertChain( serverCertRequestData, filenameBuffer,
2908 								 NULL, FALSE, FALSE, CRYPT_ALGO_ECDSA,
2909 								 48 /* P384 */ ) )
2910 			status = CRYPT_ERROR_FAILED;
2911 		}
2912 	if( cryptStatusOK( status ) )
2913 		{
2914 		printf( "done.\nSSL/TLS ECC P521 server key... " );
2915 
2916 		filenameFromTemplate( filenameBuffer, SERVER_ECPRIVKEY_FILE_TEMPLATE, 521 );
2917 		if( !writeFileCertChain( serverCertRequestData, filenameBuffer,
2918 								 NULL, FALSE, FALSE, CRYPT_ALGO_ECDSA,
2919 								 66 /* P521 */ ) )
2920 			status = CRYPT_ERROR_FAILED;
2921 		}
2922 	if( cryptStatusOK( status ) )
2923 		{
2924 		printf( "done.\nIntermediate CA key... " );
2925 		if( !writeFileCertChain( iCACertRequestData, ICA_PRIVKEY_FILE,
2926 								 NULL, FALSE, FALSE, CRYPT_ALGO_RSA,
2927 								 CRYPT_USE_DEFAULT ) )
2928 			status = CRYPT_ERROR_FAILED;
2929 		}
2930 	if( cryptStatusOK( status ) )
2931 		{
2932 		printf( "done.\nSCEP CA key + SCEP request certificate... " );
2933 		filenameFromTemplate( filenameBuffer, SCEP_CA_FILE_TEMPLATE, 1 );
2934 		if( !writeFileCertChain( scepCACertRequestData, SCEPCA_PRIVKEY_FILE,
2935 								 filenameBuffer, FALSE, FALSE, CRYPT_ALGO_RSA,
2936 								 CRYPT_USE_DEFAULT ) )
2937 			status = CRYPT_ERROR_FAILED;
2938 		}
2939 	if( cryptStatusOK( status ) )
2940 		{
2941 		printf( "done.\nTSA key... " );
2942 		if( !writeFileCertChain( tsaCertRequestData, TSA_PRIVKEY_FILE,
2943 								 NULL, FALSE, FALSE, CRYPT_ALGO_RSA,
2944 								 CRYPT_USE_DEFAULT ) )
2945 			status = CRYPT_ERROR_FAILED;
2946 		}
2947 	if( cryptStatusOK( status ) )
2948 		{
2949 		printf( "done.\nUser key... " );
2950 		filenameFromTemplate( filenameBuffer, USER_PRIVKEY_FILE_TEMPLATE, 1 );
2951 		if( !writeFileCertChain( userCertRequestData, filenameBuffer,
2952 								 NULL, FALSE, FALSE, CRYPT_ALGO_RSA,
2953 								 CRYPT_USE_DEFAULT ) )
2954 			status = CRYPT_ERROR_FAILED;
2955 		}
2956 	if( cryptStatusOK( status ) )
2957 		{
2958 		int hashAlgo = CRYPT_ALGO_NONE;
2959 
2960 		/* The following is currently redundant since the default hash is
2961 		   SHA-256 anyway, see the comment with the filenames above for
2962 		   details */
2963 		printf( "done.\nUser key using SHA256... " );
2964 		filenameFromTemplate( filenameBuffer, USER_PRIVKEY_FILE_TEMPLATE, 2 );
2965 		status = cryptGetAttribute( CRYPT_UNUSED, CRYPT_OPTION_ENCR_HASH,
2966 									&hashAlgo );
2967 		if( cryptStatusOK( status ) )
2968 			{
2969 			cryptSetAttribute( CRYPT_UNUSED, CRYPT_OPTION_ENCR_HASH,
2970 							   CRYPT_ALGO_SHA2 );
2971 			}
2972 		if( !writeFileCertChain( userCertRequestData, filenameBuffer,
2973 								 NULL, FALSE, FALSE, CRYPT_ALGO_RSA,
2974 								 CRYPT_USE_DEFAULT ) )
2975 			status = CRYPT_ERROR_FAILED;
2976 		if( hashAlgo != CRYPT_ALGO_NONE )
2977 			cryptSetAttribute( CRYPT_UNUSED, CRYPT_OPTION_ENCR_HASH,
2978 							   hashAlgo );
2979 		}
2980 	if( cryptStatusOK( status ) )
2981 		{
2982 		printf( "done.\nUser key (long chain)... " );
2983 		filenameFromTemplate( filenameBuffer, USER_PRIVKEY_FILE_TEMPLATE, 3 );
2984 		if( !writeFileCertChain( userCertRequestData, filenameBuffer,
2985 								 NULL, FALSE, TRUE, CRYPT_ALGO_RSA,
2986 								 CRYPT_USE_DEFAULT ) )
2987 			status = CRYPT_ERROR_FAILED;
2988 		}
2989 	if( cryptStatusOK( status ) )
2990 		{
2991 		CRYPT_CERTIFICATE certificate;
2992 
2993 		printf( "done.\nCertificate chain test data... " );
2994 
2995 		/* Leaf certificate */
2996 		filenameFromTemplate( filenameBuffer, USER_PRIVKEY_FILE_TEMPLATE, 3 );
2997 		status = getPublicKey( &certificate, filenameBuffer,
2998 							   USER_PRIVKEY_LABEL );
2999 		if( cryptStatusOK( status ) )
3000 			{
3001 			filenameFromTemplate( filenameBuffer, CHAINTEST_FILE_TEMPLATE,
3002 								  CHAINTEST_LEAF );
3003 			status = exportCertFile( filenameBuffer, certificate,
3004 									 CRYPT_CERTFORMAT_CERTIFICATE );
3005 			cryptDestroyCert( certificate );
3006 			}
3007 
3008 		/* Issuer (= intermediate CA) certificate */
3009 		if( cryptStatusOK( status ) )
3010 			{
3011 			status = getPublicKey( &certificate, ICA_PRIVKEY_FILE,
3012 								   USER_PRIVKEY_LABEL );
3013 			}
3014 		if( cryptStatusOK( status ) )
3015 			{
3016 			filenameFromTemplate( filenameBuffer, CHAINTEST_FILE_TEMPLATE,
3017 								  CHAINTEST_ISSUER );
3018 			status = exportCertFile( filenameBuffer, certificate,
3019 									 CRYPT_CERTFORMAT_CERTIFICATE );
3020 			cryptDestroyCert( certificate );
3021 			}
3022 
3023 		/* Root certificate */
3024 		if( cryptStatusOK( status ) )
3025 			{
3026 			status = getPublicKey( &certificate, CA_PRIVKEY_FILE,
3027 								   CA_PRIVKEY_LABEL );
3028 			}
3029 		if( cryptStatusOK( status ) )
3030 			{
3031 			filenameFromTemplate( filenameBuffer, CHAINTEST_FILE_TEMPLATE,
3032 								  CHAINTEST_ROOT );
3033 			status = exportCertFile( filenameBuffer, certificate,
3034 									 CRYPT_CERTFORMAT_CERTIFICATE );
3035 			cryptDestroyCert( certificate );
3036 			}
3037 
3038 		/* Full certificate chain */
3039 		if( cryptStatusOK( status ) )
3040 			{
3041 			filenameFromTemplate( filenameBuffer, USER_PRIVKEY_FILE_TEMPLATE, 3 );
3042 			status = getPublicKey( &certificate, filenameBuffer,
3043 								   USER_PRIVKEY_LABEL );
3044 			}
3045 		if( cryptStatusOK( status ) )
3046 			{
3047 			filenameFromTemplate( filenameBuffer, CHAINTEST_FILE_TEMPLATE,
3048 								  CHAINTEST_CHAIN );
3049 			status = exportCertFile( filenameBuffer, certificate,
3050 									 CRYPT_CERTFORMAT_CERTCHAIN );
3051 			cryptDestroyCert( certificate );
3052 			}
3053 
3054 		/* Certificate chain without root certificate */
3055 		if( cryptStatusOK( status ) )
3056 			status = writeCertChainNoRoot();
3057 
3058 		/* Certificate chain without leaf certificate */
3059 		if( cryptStatusOK( status ) )
3060 			{
3061 			status = getPublicKey( &certificate, ICA_PRIVKEY_FILE,
3062 								   USER_PRIVKEY_LABEL );
3063 			}
3064 		if( cryptStatusOK( status ) )
3065 			{
3066 			filenameFromTemplate( filenameBuffer, CHAINTEST_FILE_TEMPLATE,
3067 								  CHAINTEST_CHAIN_NOLEAF );
3068 			status = exportCertFile( filenameBuffer, certificate,
3069 									 CRYPT_CERTFORMAT_CERTCHAIN );
3070 			cryptDestroyCert( certificate );
3071 			}
3072 		}
3073 	if( cryptStatusOK( status ) )
3074 		{
3075 		printf( "done.\nSSL/TLS pseudo-certificate chain... " );
3076 		status = createPseudoCertificateFile();
3077 		}
3078 	if( cryptStatusError( status ) )
3079 		{
3080 		puts( "\nCustom key file create failed.\n" );
3081 		return( FALSE );
3082 		}
3083 	puts( "done." );
3084 
3085 	puts( "Custom key file creation succeeded.\n" );
3086 	return( TRUE );
3087 	}
3088 #endif /* 0 */
3089 
3090 #endif /* TEST_KEYSET */
3091