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