1 /* Copyright (c) 2001,2003-2006,2008 Apple Inc.
3 * keyStore.c - basic key pair store/lookup routines.
5 * create key pair, varying pub is permanent, priv is permanent;
6 * sign some data with priv;
7 * lookUpPub = lookup pub by label;
9 * lookUpPriv = lookup priv by label;
11 * ensure lookUpPriv == priv;
12 * freeKey(lookUpPriv);
13 * obtainedPriv = obtainPubFromPriv(lookUpPub);
14 * ensure obtainedPriv == priv;
15 * freeKey(obtainedPriv);
16 * delete priv; // cspwrap does implicit freeKey here...
21 * lookUpPriv = lookup priv by label; verify fail;
22 * lookUpPriv = obtainPubFromPriv(pub); verify fail;
24 * if pub is permament {
25 * lookUpPub = lookup pub by label; verify OK;
26 * deleteKey(lookUpPub);
27 * lookUpPub = lookup pub by label; verify fail;
29 * lookUpPub = lookup pub by label; verify fail;
37 #include <Security/cssm.h>
40 #include "cspdlTesting.h"
43 #define MAX_DATA_SIZE 100
44 #define DB_NAME "keyStore.db"
46 /* can't lookup non-permanent keys! */
47 #define FORCE_PUB_PERMANENT 0
49 static void usage(char **argv
)
51 printf("usage: %s [options]\n", argv
[0]);
52 printf(" Options:\n");
53 printf(" l=loops (default=%d; 0=forever)\n", LOOPS_DEF
);
54 printf(" r(RSA; default = FEE)\n");
55 printf(" p(ermanent keys, implies l=1)\n");
56 printf(" k=keyChainFile\n");
57 printf(" n(o sign/verify)\n");
58 printf(" N(o lookup of nonexistent keys)\n");
59 printf(" x (privKey always extractable)\n");
60 printf(" P(ause for MallocDebug)\n");
61 printf(" v(erbose)\n");
67 #define FEE_PRIV_DATA_SIZE 20
70 * NULL wrap, error tolerant.
72 CSSM_RETURN
cspNullWrapKey(
73 CSSM_CSP_HANDLE cspHand
,
74 const CSSM_KEY
*refKey
,
75 CSSM_KEY_PTR rawKey
) // RETURNED on success, caller must FreeKey
77 CSSM_CC_HANDLE ccHand
;
79 CSSM_ACCESS_CREDENTIALS creds
;
80 CSSM_DATA descData
= {0, 0};
82 memset(rawKey
, 0, sizeof(CSSM_KEY
));
83 memset(&creds
, 0, sizeof(CSSM_ACCESS_CREDENTIALS
));
84 crtn
= CSSM_CSP_CreateSymmetricContext(cspHand
,
87 &creds
, // passPhrase,
94 printError("cspNullWrapKey/CreateContext", crtn
);
97 crtn
= CSSM_WrapKey(ccHand
,
100 &descData
, // DescriptiveData
102 if(CSSM_DeleteContext(ccHand
)) {
103 printf("CSSM_DeleteContext failure\n");
110 * Generate key pair, default size. This is like cspGenKeyPair in cspwrap.c,
111 * tweaked for this test To allow varying permanent attribute.
113 static CSSM_RETURN
genKeyPair(CSSM_CSP_HANDLE cspHand
,
114 CSSM_DL_HANDLE dlHand
,
115 CSSM_DB_HANDLE dbHand
,
116 const CSSM_DATA_PTR keyLabel
,
117 CSSM_KEY_PTR pubKey
, // mallocd by caller
118 uint32 pubKeyUsage
, // CSSM_KEYUSE_ENCRYPT, etc.
120 CSSM_KEY_PTR privKey
, // mallocd by caller
121 uint32 privKeyUsage
, // CSSM_KEYUSE_DECRYPT, etc.
126 CSSM_CC_HANDLE ccHand
;
127 CSSM_RETURN ocrtn
= CSSM_OK
;
130 if(keyGenAlg
== CSSM_ALGID_FEE
) {
131 keySize
= CSP_FEE_KEY_SIZE_DEFAULT
;
134 keySize
= CSP_RSA_KEY_SIZE_DEFAULT
;
136 memset(pubKey
, 0, sizeof(CSSM_KEY
));
137 memset(privKey
, 0, sizeof(CSSM_KEY
));
139 crtn
= CSSM_CSP_CreateKeyGenContext(cspHand
,
149 printError("CSSM_CSP_CreateKeyGenContext", crtn
);
154 /* add in DL/DB to context */
155 crtn
= cspAddDlDbToContext(ccHand
, dlHand
, dbHand
);
160 crtn
= CSSM_GenerateKeyPair(ccHand
,
167 keyLabel
, // same labels
171 printError("CSSM_GenerateKeyPair", crtn
);
177 if(privKey
->KeyHeader
.BlobType
!= CSSM_KEYBLOB_REFERENCE
) {
178 printf("privKey blob type: exp %u got %u\n",
179 CSSM_KEYBLOB_REFERENCE
, (unsigned)privKey
->KeyHeader
.BlobType
);
181 if(pubKeyAttr
& CSSM_KEYATTR_RETURN_REF
) {
182 if(pubKey
->KeyHeader
.BlobType
!= CSSM_KEYBLOB_REFERENCE
) {
183 printf("pubKey blob type: exp %u got %u\n",
184 CSSM_KEYBLOB_REFERENCE
, (unsigned)privKey
->KeyHeader
.BlobType
);
190 if(pubKey
->KeyHeader
.BlobType
!= CSSM_KEYBLOB_RAW
) {
191 printf("pubKey blob type: exp %u got %u\n",
192 CSSM_KEYBLOB_RAW
, (unsigned)privKey
->KeyHeader
.BlobType
);
200 crtn
= CSSM_DeleteContext(ccHand
);
202 printError("CSSM_DeleteContext", crtn
);
209 #define KEY_LABEL "testKey"
212 * when true, keyref in key obtained from DL differs from
213 * keyref in key from CSP
215 #define DL_REF_KEYS_DIFFER 1
218 * ObtainPrivateKeyFromPublicKey doesn't work yet
220 #define DO_OBTAIN_FROM_PUB CSPDL_OBTAIN_PRIV_FROM_PUB
222 /* we're assumed to be logged in for access to private objects */
223 static int doTest(CSSM_CSP_HANDLE cspHand
,
224 CSSM_DL_HANDLE dlHand
,
225 CSSM_DB_HANDLE dbHand
,
226 CSSM_BOOL pubIsPerm
, // pub is permanent
227 CSSM_BOOL privIsPerm
, // priv is permanent
228 CSSM_BOOL privIsExtractable
,
229 CSSM_BOOL permKeys
, // leave them in the KC
230 CSSM_BOOL doSignVerify
,
231 CSSM_BOOL doFailedLookup
,
238 CSSM_KEY pubKey
; // from GenerateKeyPair
240 CSSM_KEY_PTR lookUpPub
; // from cspLookUpKeyByLabel, etc.
241 CSSM_KEY_PTR lookUpPriv
;
245 CSSM_KEY obtainedPriv
;
249 labelData
.Data
= (uint8
*)KEY_LABEL
;
250 labelData
.Length
= strlen(KEY_LABEL
);
253 /* create key pair */
255 printf(" ...generating key pair (pubIsPerm %d privIsPerm %d privIsExtract"
256 " %d)\n", (int)pubIsPerm
, (int)privIsPerm
, (int)privIsExtractable
);
258 pubAttr
= CSSM_KEYATTR_EXTRACTABLE
| CSSM_KEYATTR_RETURN_REF
;
260 pubAttr
|= CSSM_KEYATTR_PERMANENT
;
264 * To use a NULL wrap to test detection of !EXTRACTABLE, we're relying on
265 * being able to create !SENSITIVE private keys. We'll make 'em sensitive
266 * if we're not trying to null wrap them.
268 privAttr
= CSSM_KEYATTR_RETURN_REF
;
270 privAttr
|= CSSM_KEYATTR_PERMANENT
;
272 if(privIsExtractable
) {
273 privAttr
|= CSSM_KEYATTR_EXTRACTABLE
;
276 privAttr
|= CSSM_KEYATTR_SENSITIVE
;
278 #if CSPDL_KEYATTR_PRIVATE
279 privAttr
|= CSSM_KEYATTR_PRIVATE
;
281 crtn
= genKeyPair(cspHand
,
286 CSSM_KEYUSE_VERIFY
, // pubKeyUsage
293 return testError(quiet
);
296 /* lookUpPub = lookup pub by label; */
297 doLookup
= CSSM_TRUE
;
300 printf(" ...lookup pub by label\n");
304 printf(" ...lookup (nonexistent) pub by label\n");
307 doLookup
= CSSM_FALSE
;
313 lookUpPub
= cspLookUpKeyByLabel(dlHand
, dbHand
, &labelData
, CKT_Public
);
316 if(lookUpPub
== NULL
) {
317 printf("lookup pub by label failed\n");
318 return testError(quiet
);
321 /* sign some data with priv; */
330 return testError(quiet
);
333 /* verify header compare */
334 if(memcmp(&lookUpPub
->KeyHeader
, &pubKey
.KeyHeader
,
335 sizeof(CSSM_KEYHEADER
))) {
336 printf("**pubKey header miscompare\n");
337 return testError(quiet
);
340 /* vfy with lookUpPub; */
342 if(cspSigVerify(cspHand
,
348 return testError(quiet
);
357 if(doLookup
&& (lookUpPub
!= NULL
)) {
358 printf("***Unexpected success on cspLookUpKeyByLabel(pub, not perm)\n");
359 return testError(quiet
);
364 * Ensure proper behavior of extractable bit
367 printf(" ...null wrap %s private key\n",
368 privIsExtractable
? "EXTRACTABLE" : "!EXTRACTABLE");
370 crtn
= cspNullWrapKey(cspHand
, &privKey
, &rawPrivKey
);
371 if(privIsExtractable
) {
373 printError("Null Wrap(extractable private key)", crtn
);
374 return testError(quiet
);
377 printf(" ...free rawPrivKey\n");
379 cspFreeKey(cspHand
, &rawPrivKey
);
382 if(crtn
!= CSSMERR_CSP_INVALID_KEYATTR_MASK
) {
383 printError("Null Wrap of !extractable private key: expected "
384 "INVALID_KEYATTR_MASK, got", crtn
);
385 if(crtn
== CSSM_OK
) {
386 cspFreeKey(cspHand
, &rawPrivKey
);
388 return testError(quiet
);
391 /* lookUpPriv = lookup priv by label; ensure == privKey; */
392 doLookup
= CSSM_TRUE
;
395 printf(" ...lookup priv by label\n");
399 printf(" ...lookup (nonexistent) priv by label\n");
402 doLookup
= CSSM_FALSE
;
408 lookUpPriv
= cspLookUpKeyByLabel(dlHand
, dbHand
, &labelData
, CKT_Private
);
411 if(lookUpPriv
== NULL
) {
412 printf("lookup priv by label failed\n");
413 return testError(quiet
);
416 /* note we "know" that both keys are ref keys...*/
417 if(lookUpPriv
->KeyData
.Length
!= privKey
.KeyData
.Length
) {
418 printf("priv key data length mismatch\n");
419 return testError(quiet
);
421 #if DL_REF_KEYS_DIFFER
422 if(!memcmp(lookUpPriv
->KeyData
.Data
, privKey
.KeyData
.Data
,
423 privKey
.KeyData
.Length
)) {
424 printf("priv key ref data mismatch\n");
425 return testError(quiet
);
427 #else /* DL_REF_KEYS_DIFFER */
428 if(memcmp(lookUpPriv
->KeyData
.Data
, privKey
.KeyData
.Data
,
429 privKey
.KeyData
.Length
)) {
430 printf("unexpected priv key ref data match\n");
431 return testError(quiet
);
433 #endif /* DL_REF_KEYS_DIFFER */
435 /* verify header compare in any case */
436 if(memcmp(&lookUpPriv
->KeyHeader
, &privKey
.KeyHeader
,
437 sizeof(CSSM_KEYHEADER
))) {
438 printf("**privKey header miscompare\n");
439 return testError(quiet
);
442 /* sign with lookUpPriv, verify with pubKey */
447 printf(" ...sign with lookup priv\n");
454 return testError(quiet
);
457 printf(" ...verify with pub\n");
459 if(cspSigVerify(cspHand
,
465 printf("***sign with lookUpPriv, vfy with pub FAILED\n");
466 return testError(quiet
);
473 /* free lookUpPriv from cache, but it's permanent */
475 printf(" ...free lookupPriv\n");
477 if(cspFreeKey(cspHand
, lookUpPriv
)) {
478 printf("Error on cspFreeKey(lookUpPriv)\n");
479 return testError(quiet
);
481 CSSM_FREE(lookUpPriv
); // mallocd during lookup
484 #if DO_OBTAIN_FROM_PUB
485 /* obtainedPriv = obtainPubFromPriv(pub); ensure == priv; */
487 printf(" ...ObtainPrivateKeyFromPublicKey\n");
489 obtainedPriv
.KeyData
.Data
= NULL
;
490 obtainedPriv
.KeyData
.Length
= 0;
491 crtn
= CSSM_CSP_ObtainPrivateKeyFromPublicKey(cspHand
,
495 printError("ObtainPrivateKeyFromPublicKey", crtn
);
496 return testError(quiet
);
499 /* free obtainedPriv from cache, but it's permanent */
501 printf(" ...free obtainedPriv\n");
503 if(cspFreeKey(cspHand
, &obtainedPriv
)) {
504 printf("Error on cspFreeKey(obtainedPriv)\n");
505 return testError(quiet
);
508 #endif /* DO_OBTAIN_FROM_PUB */
511 /* delete priv - implies freeKey as well */
513 printf(" ...delete privKey\n");
515 crtn
= cspDeleteKey(cspHand
, dlHand
, dbHand
, &labelData
, &privKey
);
517 printf("Error deleting priv\n");
518 return testError(quiet
);
521 /* lookUpPriv = lookup priv by label; verify fail; */
524 printf(" ...lookup (nonexistent) priv by label\n");
526 lookUpPriv
= cspLookUpKeyByLabel(dlHand
, dbHand
, &labelData
, CKT_Private
);
527 if(lookUpPriv
!= NULL
) {
528 printf("Unexpected success on cspLookUpKeyByLabel(priv)\n");
529 return testError(quiet
);
538 /* !privIsPerm - just free it and it's all gone */
539 if(lookUpPriv
!= NULL
) {
540 printf("***Unexpected success on cspLookUpKeyByLabel(priv, not perm)\n");
541 return testError(quiet
);
544 printf(" ...free privKey\n");
546 if(cspFreeKey(cspHand
, &privKey
)) {
547 printf("Error on cspFreeKey(privKey)\n");
548 return testError(quiet
);
551 /* CSP, DL have no knowledge of privKey or its variations */
553 /* obtainedPriv = obtainPubFromPriv(pub); verify fail;*/
554 /* Note this should be safe even if DO_OBTAIN_FROM_PUB == 0 */
555 obtainedPriv
.KeyData
.Data
= NULL
;
556 obtainedPriv
.KeyData
.Length
= 0;
558 printf(" ...obtain (nonexistent) priv by public\n");
560 crtn
= CSSM_CSP_ObtainPrivateKeyFromPublicKey(cspHand
,
565 printf("Unexpected success on ObtainPrivateKeyFromPublicKey\n");
566 return testError(quiet
);
567 case CSSMERR_CSP_PRIVATE_KEY_NOT_FOUND
:
569 #if !CSPDL_OBTAIN_PRIV_FROM_PUB
570 case CSSMERR_CSP_FUNCTION_NOT_IMPLEMENTED
:
575 printf("Unexpected err ObtainPrivateKeyFromPublicKey\n");
576 printError("got this", crtn
);
577 return testError(quiet
);
580 /* free one or both copies of pub as appropriate */
582 printf(" ...free pubKey\n");
584 crtn
= cspFreeKey(cspHand
, &pubKey
);
586 printf("Error freeing pubKey\n");
587 return testError(quiet
);
591 printf(" ...free lookUpPub\n");
593 crtn
= cspFreeKey(cspHand
, lookUpPub
);
595 printf("Error freeing lookUpPub\n");
596 return testError(quiet
);
600 CSSM_FREE(lookUpPub
); // mallocd by lookup in any case
604 /* pub should still be there in DL */
605 /* lookUpPub = lookup pub by label; verify OK; */
607 printf(" ...lookup pub by label (2)\n");
609 lookUpPub
= cspLookUpKeyByLabel(dlHand
, dbHand
, &labelData
, CKT_Public
);
610 if(lookUpPub
== NULL
) {
611 printf("lookup pub by label (2) failed\n");
612 return testError(quiet
);
616 /* now really delete it */
618 printf(" ...delete lookUpPub\n");
620 crtn
= cspDeleteKey(cspHand
, dlHand
, dbHand
, &labelData
, lookUpPub
);
622 printf("Error deleting lookUpPub\n");
623 return testError(quiet
);
625 CSSM_FREE(lookUpPub
); // mallocd by lookup
628 /* else freeKey should have removed all trace */
630 if(!permKeys
&& doFailedLookup
) {
631 /* lookUpPub = lookup pub by label; verify fail; */
633 printf(" ...lookup (nonexistent) pub by label\n");
635 lookUpPub
= cspLookUpKeyByLabel(dlHand
, dbHand
, &labelData
, CKT_Public
);
636 if(lookUpPub
!= NULL
) {
637 printf("Unexpected success on cspLookUpKeyByLabel(pub) (2)\n");
638 return testError(quiet
);
644 int main(int argc
, char **argv
)
650 CSSM_CSP_HANDLE cspHand
;
651 CSSM_DB_HANDLE dbHand
;
652 CSSM_DL_HANDLE dlHand
;
654 CSSM_BOOL privIsPerm
;
655 CSSM_BOOL privIsExtractable
;
656 uint32 keyGenAlg
= CSSM_ALGID_FEE
;
657 uint32 sigAlg
= CSSM_ALGID_FEE_MD5
;
664 unsigned loops
= LOOPS_DEF
;
665 CSSM_BOOL verbose
= CSSM_FALSE
;
666 CSSM_BOOL quiet
= CSSM_FALSE
;
667 CSSM_BOOL permKeys
= CSSM_FALSE
;
668 char dbName
[100]; /* DB_NAME_pid */
669 CSSM_BOOL useExistDb
= CSSM_FALSE
;
670 CSSM_BOOL doPause
= CSSM_FALSE
;
671 CSSM_BOOL doSignVerify
= CSSM_TRUE
;
672 CSSM_BOOL doFailedLookup
= CSSM_TRUE
;
673 CSSM_BOOL privAlwaysExtractable
= CSSM_FALSE
;
677 for(arg
=1; arg
<argc
; arg
++) {
681 loops
= atoi(&argp
[2]);
690 permKeys
= CSSM_TRUE
;
694 keyGenAlg
= CSSM_ALGID_RSA
;
695 sigAlg
= CSSM_ALGID_MD5WithRSA
;
698 memmove(dbName
, &argp
[2], strlen(&argp
[2]) + 1);
699 useExistDb
= CSSM_TRUE
;
705 doSignVerify
= CSSM_FALSE
;
708 doFailedLookup
= CSSM_FALSE
;
711 privAlwaysExtractable
= CSSM_TRUE
;
719 if(dbName
[0] == '\0') {
720 sprintf(dbName
, "%s_%d", DB_NAME
, (int)getpid());
723 ptext
.Data
= (uint8
*)CSSM_MALLOC(MAX_DATA_SIZE
);
724 ptext
.Length
= MAX_DATA_SIZE
;
725 /* data generated in test loop */
726 if(ptext
.Data
== NULL
) {
727 printf("Insufficient heap\n");
731 testStartBanner("keyStore", argc
, argv
);
733 /* attach to CSP/DL */
734 cspHand
= cspDlDbStartup(CSSM_FALSE
, NULL
);
738 dlHand
= dlStartup();
743 /* this one may well require SecurityAgent UI */
744 crtn
= dbCreateOpen(dlHand
, dbName
, CSSM_FALSE
, CSSM_FALSE
, NULL
,
748 /* hands-free test */
749 crtn
= dbCreateOpen(dlHand
, dbName
, CSSM_TRUE
, CSSM_TRUE
, dbName
,
755 for(loop
=1; ; loop
++) {
758 printf("...loop %d\n", loop
);
760 appGetRandomBytes(ptext
.Data
, ptext
.Length
);
763 pubIsPerm
= privIsPerm
= CSSM_TRUE
;
766 #if CSPDL_ALL_KEYS_ARE_PERMANENT
767 pubIsPerm
= CSSM_TRUE
;
768 privIsPerm
= CSSM_TRUE
;
771 /* mix up pubIsPerm, privIsPerm */
772 pubIsPerm
= (loop
& 1) ? CSSM_TRUE
: CSSM_FALSE
;
773 privIsPerm
= (loop
& 2) ? CSSM_TRUE
: CSSM_FALSE
;
774 #if FORCE_PUB_PERMANENT
775 pubIsPerm
= CSSM_TRUE
;
777 #endif /* CSPDL_ALL_KEYS_ARE_PERMANENT */
779 privIsExtractable
= ((loop
& 4) || privAlwaysExtractable
) ? CSSM_TRUE
: CSSM_FALSE
;
787 doSignVerify
, doFailedLookup
,
796 if(loops
&& (loop
== loops
)) {
801 printf("CR to continue: ");
806 cspShutdown(cspHand
, CSSM_FALSE
);
807 /* FIXME - DB close? DL shutdown? */
808 if((rtn
== 0) && !quiet
) {
809 printf("%s test complete\n", argv
[0]);
811 if((rtn
== 0) & !permKeys
) {
812 /* be nice: if we ran OK delete the cruft DB we created */