2 * cgVerify.cpp - basic test of TP's CertGroupVerify
4 * cook up array of n key pairs;
5 * cook up cert chain to go with them;
7 * numCerts = total # of incoming certs;
8 * test one of four or five "expected result" cases {
9 * case root in certGroup but not found in AnchorCerts:
10 * certGroup = tpMakeRandCertGroup(certs[0..numCerts-1];
11 * anchorCerts = tpMakeRandCertGroup[certs[0...numCerts-2];
12 * expErr = CSSMERR_TP_INVALID_ANCHOR_CERT;
13 * expEvidenceSize = numCerts;
14 * case root in certGroup, found a copy in AnchorCerts:
15 * certGroup = tpMakeRandCertGroup(certs[0..numCerts-1];
16 * anchorCerts = tpMakeRandCertGroup[certs[0...numCerts-1];
18 * expEvidenceSize = numCerts;
19 * case verified by an AnchorCert:
20 * n = rand(1, numCerts-2);
21 * certGroup = tpMakeRandCertGroup(certs[0..n]);
22 * anchorCerts = tpMakeRandCertGroup[certs[0...numCerts-2];
24 * expEvidenceSize = n+2;
26 * n = rand(1, numCerts-3);
27 * certGroup = tpMakeRandCertGroup(certs[0..n]);
28 * anchorCerts = tpMakeRandCertGroup[certs[n+2...numCerts-2];
29 * anchorCerts may be empty....
30 * expErr = CSSMERR_TP_NOT_TRUSTED;
31 * expEvidenceSize = n+1;
32 * case incomplete public key (DSA only):
33 * root public keys is incomplete;
34 * certGroup = tpMakeRandCertGroup(certs[0..numCerts-1];
35 * anchorCerts = tpMakeRandCertGroup[certs[0...numCerts-1];
37 * expEvidenceSize = numCerts;
39 * result = certGroupVerify();
40 * verify expected result and getError();
41 * delete certs from DB;
45 #include <Security/cssm.h>
46 #include <utilLib/common.h>
47 #include <utilLib/cspwrap.h>
48 #include <clAppUtils/clutils.h>
49 #include <clAppUtils/tpUtils.h>
50 #include <clAppUtils/timeStr.h>
51 #include <utilLib/nssAppUtils.h>
52 #include <security_cdsa_utils/cuFileIo.h>
57 #include <sys/types.h>
59 #include <Security/oidsalg.h>
61 #define NUM_CERTS_DEF 10
62 #define KEYGEN_ALG_DEF CSSM_ALGID_RSA
63 #define SIG_ALG_DEF CSSM_ALGID_SHA1WithRSA
65 #define SECONDS_TO_LIVE (60 * 60 * 24) /* certs are valid for this long */
66 //#define SECONDS_TO_LIVE 5
69 #define DB_NAME "cgVerify.db"
70 #define DSA_PARAM_FILE "dsaParam512.der"
73 * How we define the "expected result".
76 ER_InvalidAnchor
, // root in certGroup, not found in AnchorCerts
77 ER_RootInCertGroup
, // root in certGroup, copy in AnchorCerts
78 ER_AnchorVerify
, // end of chain verified by an anchor
79 ER_NoRoot
, // no root, no anchor verify
80 ER_IncompleteKey
// un-completable public key (all keys are partial), DSA
84 static void usage(char **argv
)
86 printf("Usage: %s [options]\n", argv
[0]);
87 printf(" Options:\n");
88 printf(" n=numCerts; default = %d\n", NUM_CERTS_DEF
);
89 printf(" l=loops; default=%d; 0=forever\n", LOOPS_DEF
);
90 printf(" a=alg (f=FEE/MD5, F=FEE/SHA1, e=FEE/ECDSA, s=RSA/SHA1, m=RSA/MD5,\n");
91 printf(" d=DSA, 4=RSA/SHA224, 6=RSA/SHA256, 3=RSA/SHA384, 5=RSA/SHA512,\n");
92 printf(" E=ANSI/ECDSA, 7=ECDSA/SHA256; default = RSA/SHA1\n");
93 printf(" k=keySizeInBits\n");
94 printf(" d(isable DB)\n");
95 printf(" P(ause on each loop)\n");
96 printf(" N (no partial pub keys)\n");
97 printf(" v(erbose)\n");
104 CSSM_TP_HANDLE tpHand
,
105 CSSM_CL_HANDLE clHand
,
106 CSSM_CSP_HANDLE cspHand
,
107 CSSM_DL_DB_HANDLE dlDb
,
110 CSSM_KEY_PTR pubKeys
, // for partial key detect
112 ExpectResult expectResult
,
116 unsigned cgEnd
; // last cert in certGroupFrag
117 unsigned anchorStart
; // first cert in anchorGroup
118 unsigned anchorEnd
; // last cert in anchorGroup
119 CSSM_CERTGROUP certGroupFrag
; // INPUT to CertGroupVerify
120 CSSM_CERTGROUP anchorCerts
; // ditto
121 unsigned die
; // random number
122 CSSM_DL_DB_LIST dbList
;
123 CSSM_DL_DB_LIST_PTR dbListPtr
;
124 CSSM_RETURN expErr
; // expected rtn from GroupVfy()
126 const char *expResStr
;
127 uint32 expEvidenceSize
; // expected evidenceSize
128 unsigned evidenceSize
; // actual evidence size
129 CSSM_TP_VERIFY_CONTEXT_RESULT vfyResult
;
130 CSSM_CERTGROUP_PTR outGrp
= NULL
;
132 CSSM_DL_DB_HANDLE_PTR dlDbPtr
;
135 memset(&vfyResult
, 0, sizeof(CSSM_TP_VERIFY_CONTEXT_RESULT
));
139 dbList
.NumHandles
= 1;
140 dbList
.DLDBHandle
= &dlDb
;
149 /* the four test cases */
150 switch(expectResult
) {
151 case ER_InvalidAnchor
:
152 /* root in certGroup, not found in AnchorCerts */
153 cgEnd
= numCerts
- 1; // certGroupFrag is the whole pile
154 anchorStart
= 0; // anchors = all except root
155 anchorEnd
= numCerts
- 2;
156 expErr
= CSSMERR_TP_INVALID_ANCHOR_CERT
;
157 expEvidenceSize
= numCerts
;
158 expResStr
= "InvalidAnchor (root in certGroup but not in anchors)";
161 case ER_RootInCertGroup
:
162 /* root in certGroup, copy in AnchorCerts */
163 cgEnd
= numCerts
- 1; // certGroupFrag = the whole pile
164 anchorStart
= 0; // anchors = the whole pile
165 anchorEnd
= numCerts
- 1;
167 expEvidenceSize
= numCerts
;
168 expResStr
= "Good (root in certGroup AND in anchors)";
171 case ER_AnchorVerify
:
172 /* non-root end of chain verified by an anchor */
173 /* break chain at random place other than end */
174 /* die is the last cert in certGroupFrag */
175 die
= genRand(0, numCerts
-2);
176 cgEnd
= die
; // certGroupFrag up to break point
177 anchorStart
= 0; // anchors = all
178 anchorEnd
= numCerts
- 1;
179 if(pubKeys
[die
+1].KeyHeader
.KeyAttr
& CSSM_KEYATTR_PARTIAL
) {
180 /* this will fail due to an unusable anchor */
181 expErr
= CSSMERR_TP_CERTIFICATE_CANT_OPERATE
;
182 expResStr
= "Root ONLY in anchors but has partial pub key";
186 expResStr
= "Good (root ONLY in anchors)";
188 /* size = # certs in certGroupFrag, plus one anchor */
189 expEvidenceSize
= die
+ 2;
193 /* no root, no anchor verify */
194 /* break chain at random place other than end */
195 /* die is the last cert in certGroupFrag */
196 /* skip a cert, then anchors start at die + 2 */
197 die
= genRand(0, numCerts
-2);
198 cgEnd
= die
; // certGroupFrag up to break point
199 anchorStart
= die
+ 2; // anchors = n+1...numCerts-2
200 // may be empty if n == numCerts-2
201 anchorEnd
= numCerts
- 2;
202 if((die
!= 0) && // partial leaf not reported as partial!
203 (pubKeys
[die
].KeyHeader
.KeyAttr
& CSSM_KEYATTR_PARTIAL
)) {
204 /* this will fail due to an unusable cert (this one) */
205 expErr
= CSSMERR_TP_CERTIFICATE_CANT_OPERATE
;
206 expResStr
= "Not Trusted (no root, no anchor verify), partial";
209 expErr
= CSSMERR_TP_NOT_TRUSTED
;
210 expResStr
= "Not Trusted (no root, no anchor verify)";
212 expEvidenceSize
= die
+ 1;
215 case ER_IncompleteKey
:
217 * Anchor has incomplete pub key
218 * Root in certGroup, copy in AnchorCerts
219 * Avoid putting anchor in certGroupFrag because the TP will think
220 * it's NOT a root and it'll show up twice in the evidence - once
221 * from certGroupFrag (at which point the search for a root
222 * keeps going), and once from Anchors.
224 cgEnd
= numCerts
- 2; // certGroupFrag = the whole pile less the anchor
225 anchorStart
= 0; // anchors = the whole pile
226 anchorEnd
= numCerts
- 1;
227 expErr
= CSSMERR_TP_CERTIFICATE_CANT_OPERATE
;
228 expEvidenceSize
= numCerts
;
229 expResStr
= "Partial public key in anchor";
234 printf(" ...expectResult = %s\n", expResStr
);
237 /* cook up two cert groups */
239 printf(" ...building certGroupFrag from certs[0..%d]\n",
242 if(tpMakeRandCertGroup(clHand
,
244 certs
, // certGroupFrag always starts at 0
245 cgEnd
+1, // # of certs
247 CSSM_TRUE
, // firstCertIsSubject
249 CSSM_FALSE
, // allInDbs
250 CSSM_FALSE
)) { // skipFirstDb
251 printf("Error in tpMakeRandCertGroup\n");
256 printf(" ...building anchorCerts from certs[%d..%d]\n",
257 anchorStart
, anchorEnd
);
259 if(anchorEnd
> (numCerts
- 1)) {
260 printf("anchorEnd overflow\n");
263 if(anchorStart
>= anchorEnd
) {
264 /* legal in some corner cases, ==> empty enchors */
268 numAnchors
= anchorEnd
- anchorStart
+ 1;
270 /* anchors do not go in DB */
271 if(tpMakeRandCertGroup(clHand
,
274 numAnchors
, // # of certs
276 CSSM_FALSE
, // firstCertIsSubject
278 CSSM_FALSE
, // allInDbs
279 CSSM_FALSE
)) { // skipFirstDb
280 printf("Error in tpMakeRandCertGroup\n");
284 crtn
= tpCertGroupVerify(
289 &CSSMOID_APPLE_X509_BASIC
, // policy
294 anchorCerts
.GroupList
.CertList
, // passed as CSSM_DATA_PTR, not CERTGROUP....
295 anchorCerts
.NumCerts
,
296 CSSM_TP_STOP_ON_POLICY
,
300 /* first verify format of result */
301 if( (vfyResult
.NumberOfEvidences
!= 3) ||
302 (vfyResult
.Evidence
== NULL
) ||
303 (vfyResult
.Evidence
[0].EvidenceForm
!= CSSM_EVIDENCE_FORM_APPLE_HEADER
) ||
304 (vfyResult
.Evidence
[1].EvidenceForm
!= CSSM_EVIDENCE_FORM_APPLE_CERTGROUP
) ||
305 (vfyResult
.Evidence
[2].EvidenceForm
!= CSSM_EVIDENCE_FORM_APPLE_CERT_INFO
) ||
306 (vfyResult
.Evidence
[0].Evidence
== NULL
) ||
307 (vfyResult
.Evidence
[1].Evidence
== NULL
) ||
308 (vfyResult
.Evidence
[2].Evidence
== NULL
)) {
309 printf("***Malformed VerifyContextResult\n");
310 rtn
= testError(quiet
);
315 if((vfyResult
.Evidence
!= NULL
) && (vfyResult
.Evidence
[1].Evidence
!= NULL
)) {
316 outGrp
= (CSSM_CERTGROUP_PTR
)vfyResult
.Evidence
[1].Evidence
;
317 evidenceSize
= outGrp
->NumCerts
;
320 /* in case no evidence returned */
324 /* %%% since non-root anchors are permitted as of <rdar://5685316>,
325 * the test assumptions have become invalid: these tests generate
326 * an anchors list which always includes the full chain, so by
327 * definition, the evidence chain will never be longer than 2,
328 * since the leaf's issuer is always an anchor.
329 * %%% need to revisit and rewrite these tests. -kcm
331 if ((evidenceSize
> 1) && (evidenceSize
< expEvidenceSize
) &&
332 (crtn
== CSSM_OK
|| crtn
== CSSMERR_TP_CERTIFICATE_CANT_OPERATE
)) {
333 /* ignore, for now */
335 expEvidenceSize
= evidenceSize
;
338 if((crtn
!= expErr
) ||
339 (evidenceSize
!= expEvidenceSize
)) {
340 printf("***Error on expectResult %s\n", expResStr
);
341 printf(" err %s expErr %s\n",
342 cssmErrToStr(crtn
), cssmErrToStr(expErr
));
343 printf(" evidenceSize %d expEvidenceSize %u\n",
344 evidenceSize
, (unsigned)expEvidenceSize
);
345 rtn
= testError(quiet
);
352 tpFreeCertGroup(&certGroupFrag
,
353 CSSM_FALSE
, // caller malloc'd the actual certs
354 CSSM_FALSE
); // struct is on stack
355 tpFreeCertGroup(&anchorCerts
,
356 CSSM_FALSE
, // caller malloc'd the actual certs
357 CSSM_FALSE
); // struct is on stack
358 freeVfyResult(&vfyResult
);
360 clDeleteAllCerts(dlDb
);
365 int main(int argc
, char **argv
)
370 CSSM_TP_HANDLE tpHand
= 0;
371 CSSM_CL_HANDLE clHand
= 0;
372 CSSM_CSP_HANDLE cspHand
= 0;
373 CSSM_DL_DB_HANDLE dlDbHand
= {0, 0};
374 ExpectResult expectResult
;
379 CSSM_DATA_PTR paramDataP
= NULL
;
380 unsigned numTests
= 4;
383 /* all three of these are arrays with numCert elements */
384 CSSM_KEY_PTR pubKeys
= NULL
;
385 CSSM_KEY_PTR privKeys
= NULL
;
386 CSSM_DATA_PTR certs
= NULL
;
388 /* Keys do NOT go in the cert DB */
389 CSSM_DL_DB_HANDLE keyDb
= {0, 0};
390 CSSM_KEY savedRoot
; // for ER_IncompleteKey
395 unsigned loops
= LOOPS_DEF
;
396 CSSM_BOOL verbose
= CSSM_FALSE
;
397 CSSM_BOOL quiet
= CSSM_FALSE
;
398 unsigned numCerts
= NUM_CERTS_DEF
;
399 uint32 keyGenAlg
= KEYGEN_ALG_DEF
;
400 uint32 sigAlg
= SIG_ALG_DEF
;
402 CSSM_BOOL useDb
= CSSM_TRUE
;
404 CSSM_BOOL useDb
= CSSM_FALSE
;
406 CSSM_BOOL doPause
= CSSM_FALSE
;
407 uint32 keySizeInBits
= CSP_KEY_SIZE_DEFAULT
;
408 CSSM_BOOL noPartialKeys
= CSSM_FALSE
;
409 char dbName
[100]; /* DB_NAME_pid */
411 for(arg
=1; arg
<argc
; arg
++) {
415 loops
= atoi(&argp
[2]);
418 keySizeInBits
= atoi(&argp
[2]);
421 numCerts
= atoi(&argp
[2]);
432 keyGenAlg
= CSSM_ALGID_FEE
;
433 sigAlg
= CSSM_ALGID_FEE_MD5
;
436 keyGenAlg
= CSSM_ALGID_FEE
;
437 sigAlg
= CSSM_ALGID_FEE_SHA1
;
440 keyGenAlg
= CSSM_ALGID_FEE
;
441 sigAlg
= CSSM_ALGID_SHA1WithECDSA
;
444 keyGenAlg
= CSSM_ALGID_RSA
;
445 sigAlg
= CSSM_ALGID_SHA1WithRSA
;
448 keyGenAlg
= CSSM_ALGID_RSA
;
449 sigAlg
= CSSM_ALGID_MD5WithRSA
;
452 keyGenAlg
= CSSM_ALGID_DSA
;
453 sigAlg
= CSSM_ALGID_SHA1WithDSA
;
456 keyGenAlg
= CSSM_ALGID_RSA
;
457 sigAlg
= CSSM_ALGID_SHA224WithRSA
;
460 keyGenAlg
= CSSM_ALGID_RSA
;
461 sigAlg
= CSSM_ALGID_SHA256WithRSA
;
464 keyGenAlg
= CSSM_ALGID_RSA
;
465 sigAlg
= CSSM_ALGID_SHA512WithRSA
;
468 keyGenAlg
= CSSM_ALGID_RSA
;
469 sigAlg
= CSSM_ALGID_SHA512WithRSA
;
472 keyGenAlg
= CSSM_ALGID_ECDSA
;
473 sigAlg
= CSSM_ALGID_SHA1WithECDSA
;
476 keyGenAlg
= CSSM_ALGID_ECDSA
;
477 sigAlg
= CSSM_ALGID_SHA512WithECDSA
;
484 noPartialKeys
= CSSM_TRUE
;
498 sprintf(dbName
, "%s_%d", DB_NAME
, (int)getpid());
501 printf("Can't run with cert chain smaller than 2\n");
505 /* attach to all the modules we need */
506 cspHand
= cspStartup();
512 dlDbHand
.DLHandle
= dlStartup();
513 if(dlDbHand
.DLHandle
== 0) {
516 CSSM_RETURN crtn
= tpKcOpen(dlDbHand
.DLHandle
, dbName
, dbName
,
517 CSSM_TRUE
, &dlDbHand
.DBHandle
);
519 printf("Error opening keychain %s; aborting.\n", dbName
);
524 clHand
= clStartup();
528 tpHand
= tpStartup();
533 /* malloc empty keys and certs */
534 pubKeys
= (CSSM_KEY_PTR
)CSSM_CALLOC(numCerts
, sizeof(CSSM_KEY
));
535 privKeys
= (CSSM_KEY_PTR
)CSSM_CALLOC(numCerts
, sizeof(CSSM_KEY
));
536 certs
= (CSSM_DATA_PTR
)CSSM_CALLOC(numCerts
, sizeof(CSSM_DATA
));
537 if((pubKeys
== NULL
) || (privKeys
== NULL
) || (certs
== NULL
)) {
538 printf("not enough memory for %u keys pairs and certs.\n",
543 printf("Starting cgVerify; args: ");
544 for(i
=1; i
<(unsigned)argc
; i
++) {
545 printf("%s ", argv
[i
]);
549 /* generate key pairs */
551 printf("generating keys...\n");
553 if(keyGenAlg
== CSSM_ALGID_DSA
) {
554 if(!readFile(DSA_PARAM_FILE
, (unsigned char **)¶mData
.Data
, &len
)) {
556 printf("...using DSA params from %s\n", DSA_PARAM_FILE
);
558 paramData
.Length
= len
;
559 paramDataP
= ¶mData
;
562 printf("***warning: no param file. KeyGen is going to be slow!\n");
563 printf("***You might consider running this from the clxutils/cgVerify "
567 if(tpGenKeys(cspHand
,
572 "cgVerify", // keyLabelBase
578 notBeforeStr
= genTimeAtNowPlus(0);
579 notAfterStr
= genTimeAtNowPlus(SECONDS_TO_LIVE
);
582 * If DSA, insert some random partial public keys which are not
583 * fatal (i.e., root can not be partial). We include the leaf in this
584 * loop - the TP is *supposed* to ignore that situation, ane we make
587 if((keyGenAlg
== CSSM_ALGID_DSA
) && !noPartialKeys
) {
588 for(unsigned dex
=0; dex
<(numCerts
-1); dex
++) {
589 int die
= genRand(0,1);
591 /* this one gets partialized */
594 printf("...making partial DSA pub key at index %u\n", dex
);
596 CSSM_RETURN crtn
= extractDsaPartial(cspHand
, &pubKeys
[dex
], &newKey
);
598 printf("***Error converting to partial key. Aborting.\n");
601 CSSM_FREE(pubKeys
[dex
].KeyData
.Data
);
602 pubKeys
[dex
] = newKey
;
607 printf("starting %s test\n", argv
[0]);
610 if(keyGenAlg
== CSSM_ALGID_DSA
) {
613 for(loop
=1; ; loop
++) {
615 printf("...loop %d\n", loop
);
618 /* cycle thru test scenarios */
619 switch(loop
% numTests
) {
621 expectResult
= ER_InvalidAnchor
;
624 expectResult
= ER_RootInCertGroup
;
627 expectResult
= ER_AnchorVerify
;
630 expectResult
= ER_NoRoot
;
634 expectResult
= ER_IncompleteKey
;
635 savedRoot
= pubKeys
[numCerts
-1];
636 /* make anchor unusable */
637 if(extractDsaPartial(cspHand
, &savedRoot
, &pubKeys
[numCerts
-1])) {
638 printf("...error partializing anchor key; aborting\n");
643 if(tpGenCerts(cspHand
,
647 "cgConstruct", // nameBase
669 for(i
=0; i
<numCerts
; i
++) {
670 appFreeCssmData(&certs
[i
], CSSM_FALSE
);
672 if(expectResult
== ER_IncompleteKey
) {
673 CSSM_FREE(pubKeys
[numCerts
-1].KeyData
.Data
);
674 pubKeys
[numCerts
-1] = savedRoot
;
677 memset(certs
, 0, numCerts
* sizeof(CSSM_DATA
));
678 if(loops
&& (loop
== loops
)) {
682 printf("Hit CR to continue: ");
688 if(privKeys
!= NULL
) {
689 for(i
=0; i
<numCerts
; i
++) {
690 if(privKeys
[i
].KeyData
.Data
!= NULL
) {
691 cspFreeKey(cspHand
, &privKeys
[i
]);
696 if(pubKeys
!= NULL
) {
697 for(i
=0; i
<numCerts
; i
++) {
698 if(pubKeys
[i
].KeyData
.Data
!= NULL
) {
699 cspFreeKey(cspHand
, &pubKeys
[i
]);
705 for(i
=0; i
<numCerts
; i
++) {
706 appFreeCssmData(&certs
[i
], CSSM_FALSE
);
711 CSSM_ModuleDetach(cspHand
);
714 CSSM_ModuleDetach(clHand
);
717 CSSM_ModuleDetach(tpHand
);
721 printf("%s test complete\n", argv
[0]);