]>
Commit | Line | Data |
---|---|---|
d8f41ccd A |
1 | /* cgVerifyThr.cpp - simple version CertGroupVerify test */ |
2 | ||
3 | #include "testParams.h" | |
4 | #include <Security/cssm.h> | |
5 | #include <utilLib/common.h> | |
6 | #include <utilLib/cspwrap.h> | |
7 | #include <clAppUtils/clutils.h> | |
8 | #include <clAppUtils/tpUtils.h> | |
9 | #include <clAppUtils/timeStr.h> | |
10 | #include <stdio.h> | |
11 | #include <stdlib.h> | |
12 | #include <time.h> | |
13 | #include <string.h> | |
14 | #include <Security/oidsalg.h> | |
15 | ||
16 | /* for memory leak debug only, with only one thread running */ | |
17 | #define DO_PAUSE 0 | |
18 | ||
19 | /*** start of code directly copied from ../cgVerify/cgVerify.cpp ***/ | |
20 | #define NUM_CERTS_MIN 4 | |
21 | #define KEYGEN_ALG_DEF CSSM_ALGID_RSA | |
22 | #define SIG_ALG_DEF CSSM_ALGID_SHA1WithRSA | |
23 | #define LOOPS_DEF 10 | |
24 | #define CG_KEY_SIZE_DEFAULT CSP_RSA_KEY_SIZE_DEFAULT | |
25 | #define SECONDS_TO_LIVE (60 * 60 * 24) /* certs are valid for this long */ | |
26 | ||
27 | #define CERT_IN_DB 0 | |
28 | ||
29 | /* | |
30 | * How we define the "expected result". | |
31 | */ | |
32 | typedef enum { | |
33 | ER_InvalidAnchor, // root in certGroup, not found in AnchorCerts | |
34 | ER_RootInCertGroup, // root in certGroup, copy in AnchorCerts | |
35 | ER_AnchorVerify, // end of chain verified by an anchor | |
36 | ER_NoRoot // no root, no anchor verify | |
37 | } ExpectResult; | |
38 | ||
39 | static int testError() | |
40 | { | |
41 | char resp; | |
42 | ||
43 | printf("Attach via debugger for more info.\n"); | |
44 | printf("a to abort, c to continue: "); | |
45 | resp = getchar(); | |
46 | return (resp == 'a'); | |
47 | } | |
48 | ||
49 | static int doTest( | |
50 | CSSM_TP_HANDLE tpHand, | |
51 | CSSM_CL_HANDLE clHand, | |
52 | CSSM_CSP_HANDLE cspHand, | |
53 | CSSM_DL_DB_HANDLE dlDb, | |
54 | CSSM_DATA_PTR certs, | |
55 | unsigned numCerts, | |
56 | CSSM_BOOL useDb, | |
57 | ExpectResult expectResult, | |
58 | CSSM_BOOL verbose) | |
59 | { | |
60 | unsigned cgEnd; // last cert in certGroupFrag | |
61 | unsigned anchorStart; // first cert in anchorGroup | |
62 | unsigned anchorEnd; // last cert in anchorGroup | |
63 | CSSM_CERTGROUP certGroupFrag; // INPUT to CertGroupVerify | |
64 | CSSM_CERTGROUP anchorCerts; // ditto | |
65 | unsigned die; // random number | |
66 | CSSM_DL_DB_LIST dbList; | |
67 | CSSM_DL_DB_LIST_PTR dbListPtr; | |
68 | CSSM_DL_DB_HANDLE_PTR dlDbPtr; | |
69 | CSSM_RETURN expErr; // expected rtn from GroupVfy() | |
70 | int rtn = 0; | |
71 | const char *expResStr; | |
72 | uint32 expEvidenceSize; // expected evidenceSize | |
73 | unsigned evidenceSize; // actual evidence size | |
74 | CSSM_TP_VERIFY_CONTEXT_RESULT vfyResult; | |
75 | CSSM_CERTGROUP_PTR outGrp = NULL; | |
76 | CSSM_RETURN crtn; | |
77 | ||
78 | memset(&vfyResult, 0, sizeof(CSSM_TP_VERIFY_CONTEXT_RESULT)); | |
79 | ||
80 | if(useDb) { | |
81 | dlDbPtr = &dlDb; | |
82 | dbList.NumHandles = 1; | |
83 | dbList.DLDBHandle = &dlDb; | |
84 | dbListPtr = &dbList; | |
85 | } | |
86 | else { | |
87 | /* not yet */ | |
88 | dlDbPtr = NULL; | |
89 | dbListPtr = NULL; | |
90 | } | |
91 | ||
92 | /* the four test cases */ | |
93 | switch(expectResult) { | |
94 | case ER_InvalidAnchor: | |
95 | /* root in certGroup, not found in AnchorCerts */ | |
96 | cgEnd = numCerts - 1; // certGroupFrag is the whole pile | |
97 | anchorStart = 0; // anchors = all except root | |
98 | anchorEnd = numCerts - 2; | |
99 | expErr = CSSMERR_TP_INVALID_ANCHOR_CERT; | |
100 | expEvidenceSize = numCerts; | |
101 | expResStr = "InvalidAnchor (root in certGroup but not in anchors)"; | |
102 | break; | |
103 | ||
104 | case ER_RootInCertGroup: | |
105 | /* root in certGroup, copy in AnchorCerts */ | |
106 | cgEnd = numCerts - 1; // certGroupFrag = the whole pile | |
107 | anchorStart = 0; // anchors = the whole pile | |
108 | anchorEnd = numCerts - 1; | |
109 | expErr = CSSM_OK; | |
110 | expEvidenceSize = numCerts; | |
111 | expResStr = "Good (root in certGroup AND in anchors)"; | |
112 | break; | |
113 | ||
114 | case ER_AnchorVerify: | |
115 | /* non-root end of chain verified by an anchor */ | |
116 | /* break chain at random place other than start and end-2 */ | |
117 | die = genRand(1, numCerts-3); | |
118 | cgEnd = die; // certGroupFrag up to break point | |
119 | anchorStart = 0; // anchors = all | |
120 | anchorEnd = numCerts - 1; | |
121 | expErr = CSSM_OK; | |
122 | /* size = # certs in certGroupFrag, plus one anchor */ | |
123 | expEvidenceSize = die + 2; | |
124 | expResStr = "Good (root ONLY in anchors)"; | |
125 | break; | |
126 | ||
127 | case ER_NoRoot: | |
128 | /* no root, no anchor verify */ | |
129 | /* break chain at random place other than start and end-1 */ | |
130 | die = genRand(1, numCerts-2); | |
131 | cgEnd = die; // certGroupFrag up to break point | |
132 | /* and skip one cert */ | |
133 | anchorStart = die + 2; // anchors = n+1...numCerts-2 | |
134 | // may be empty if n == numCerts-2 | |
135 | anchorEnd = numCerts - 1; | |
136 | expErr = CSSMERR_TP_NOT_TRUSTED; | |
137 | expEvidenceSize = die + 1; | |
138 | expResStr = "Not Trusted (no root, no anchor verify)"; | |
139 | break; | |
140 | } | |
141 | ||
142 | if(verbose) { | |
143 | printf(" ...expectResult = %s\n", expResStr); | |
144 | } | |
145 | ||
146 | /* cook up two cert groups */ | |
147 | if(verbose) { | |
148 | printf(" ...building certGroupFrag from certs[0..%d]\n", | |
149 | cgEnd); | |
150 | } | |
151 | if(tpMakeRandCertGroup(clHand, | |
152 | dbListPtr, | |
153 | certs, // certGroupFrag always starts at 0 | |
154 | cgEnd+1, // # of certs | |
155 | &certGroupFrag, | |
156 | CSSM_TRUE, // firstCertIsSubject | |
157 | verbose, | |
158 | CSSM_FALSE, // allInDbs | |
159 | CSSM_FALSE)) { // skipFirstDb | |
160 | printf("\nError in tpMakeRandCertGroup\n"); | |
161 | return 1; | |
162 | } | |
163 | ||
164 | if(anchorStart > anchorEnd) { | |
165 | /* legal for ER_NoRoot */ | |
166 | if((expectResult != ER_NoRoot) || (anchorStart != numCerts)) { | |
167 | printf("Try again, pal.\n"); | |
168 | exit(1); | |
169 | } | |
170 | } | |
171 | if(verbose) { | |
172 | printf(" ...building anchorCerts from certs[%d..%d]\n", | |
173 | anchorStart, anchorEnd); | |
174 | } | |
175 | if(anchorEnd > (numCerts - 1)) { | |
176 | printf("anchorEnd overflow\n"); | |
177 | exit(1); | |
178 | } | |
179 | /* anchors do not go in DB */ | |
180 | if(tpMakeRandCertGroup(clHand, | |
181 | NULL, | |
182 | certs + anchorStart, | |
183 | anchorEnd - anchorStart + 1, // # of certs | |
184 | &anchorCerts, | |
185 | CSSM_FALSE, // firstCertIsSubject | |
186 | verbose, | |
187 | CSSM_FALSE, // allInDbs | |
188 | CSSM_FALSE)) { // skipFirstDb | |
189 | printf("\nError in tpMakeRandCertGroup\n"); | |
190 | return 1; | |
191 | } | |
192 | ||
193 | crtn = tpCertGroupVerify( | |
194 | tpHand, | |
195 | clHand, | |
196 | cspHand, | |
197 | dbListPtr, | |
198 | &CSSMOID_APPLE_X509_BASIC, // Policy | |
199 | NULL, // fieldOpts | |
200 | NULL, // actionData | |
201 | NULL, // policyOpts | |
202 | &certGroupFrag, | |
203 | anchorCerts.GroupList.CertList, // passed as CSSM_DATA_PTR, not CERTGROUP.... | |
204 | anchorCerts.NumCerts, | |
205 | CSSM_TP_STOP_ON_POLICY, | |
206 | NULL, // cssmTimeStr | |
207 | &vfyResult); | |
208 | ||
209 | /* first verify format of result */ | |
210 | if( (vfyResult.NumberOfEvidences != 3) || | |
211 | (vfyResult.Evidence == NULL) || | |
212 | (vfyResult.Evidence[0].EvidenceForm != CSSM_EVIDENCE_FORM_APPLE_HEADER) || | |
213 | (vfyResult.Evidence[1].EvidenceForm != CSSM_EVIDENCE_FORM_APPLE_CERTGROUP) || | |
214 | (vfyResult.Evidence[2].EvidenceForm != CSSM_EVIDENCE_FORM_APPLE_CERT_INFO) || | |
215 | (vfyResult.Evidence[0].Evidence == NULL) || | |
216 | (vfyResult.Evidence[1].Evidence == NULL) || | |
217 | (vfyResult.Evidence[2].Evidence == NULL)) { | |
218 | printf("***Malformed VerifyContextResult\n"); | |
219 | return 1; | |
220 | } | |
221 | if((vfyResult.Evidence != NULL) && (vfyResult.Evidence[1].Evidence != NULL)) { | |
222 | outGrp = (CSSM_CERTGROUP_PTR)vfyResult.Evidence[1].Evidence; | |
223 | evidenceSize = outGrp->NumCerts; | |
224 | } | |
225 | else { | |
226 | /* in case no evidence returned */ | |
227 | evidenceSize = 0; | |
228 | } | |
229 | ||
230 | /* %%% since non-root anchors are permitted as of <rdar://5685316>, | |
231 | * the test assumptions have become invalid: these tests generate | |
232 | * an anchors list which always includes the full chain, so by | |
233 | * definition, the evidence chain will never be longer than 2, | |
234 | * since the leaf's issuer is always an anchor. | |
235 | * %%% need to revisit and rewrite these tests. -kcm | |
236 | */ | |
237 | if ((evidenceSize > 1) && (evidenceSize < expEvidenceSize) && | |
238 | (crtn == CSSM_OK || crtn == CSSMERR_TP_CERTIFICATE_CANT_OPERATE)) { | |
239 | /* ignore, for now */ | |
240 | expErr = crtn; | |
241 | expEvidenceSize = evidenceSize; | |
242 | } | |
243 | ||
244 | if((crtn != expErr) || | |
245 | (evidenceSize != expEvidenceSize)) { | |
246 | printf("\n***cgVerify: Error on tpCertGroupVerify expectResult %s\n", | |
247 | expResStr); | |
248 | printf(" err %s expErr %s\n", | |
249 | cssmErrToStr(crtn), cssmErrToStr(expErr)); | |
250 | printf(" evidenceSize %d expEvidenceSize %u\n", | |
251 | evidenceSize, (unsigned)expEvidenceSize); | |
252 | printf(" numCerts %d cgEnd %d anchorStart %d anchorEnd %d\n", | |
253 | numCerts, cgEnd, anchorStart, anchorEnd); | |
254 | rtn = testError(); | |
255 | } | |
256 | else { | |
257 | rtn = 0; | |
258 | } | |
259 | ||
260 | /* free resources */ | |
261 | tpFreeCertGroup(&certGroupFrag, | |
262 | CSSM_FALSE, // caller malloc'd the actual certs | |
263 | CSSM_FALSE); // struct is on stack | |
264 | tpFreeCertGroup(&anchorCerts, | |
265 | CSSM_FALSE, // caller malloc'd the actual certs | |
266 | CSSM_FALSE); // struct is on stack | |
267 | freeVfyResult(&vfyResult); | |
268 | if(useDb) { | |
269 | clDeleteAllCerts(dlDb); | |
270 | } | |
271 | return rtn; | |
272 | } | |
273 | ||
274 | /*** end of code directly copied from ../cgVerify/cgVerify.cpp ***/ | |
275 | ||
276 | /* | |
277 | * For debug only - ensure that the given array of public keys are all unique | |
278 | * Only saw this when using FEE RNG (i.e., no SecurityServer running). | |
279 | */ | |
280 | int comparePubKeys( | |
281 | unsigned numKeys, | |
282 | const CSSM_KEY *pubKeys) | |
283 | { | |
284 | unsigned i,j; | |
285 | ||
286 | for(i=0; i<numKeys-1; i++) { | |
287 | for(j=i+1; j<numKeys; j++) { | |
288 | if(appCompareCssmData(&pubKeys[i].KeyData, &pubKeys[j].KeyData)) { | |
289 | printf("***HEY! DUPLICATE PUBLIC KEYS in cgVerify!\n"); | |
290 | return testError(); | |
291 | } | |
292 | } | |
293 | } | |
294 | return 0; | |
295 | } | |
296 | ||
297 | ||
298 | /* | |
299 | * key pairs - created in cgConstructInit, stored in testParams->perThread | |
300 | */ | |
301 | typedef struct { | |
302 | CSSM_KEY_PTR pubKeys; | |
303 | CSSM_KEY_PTR privKeys; | |
304 | unsigned numKeys; | |
305 | char *notBeforeStr; // to use thread-safe tpGenCerts() | |
306 | char *notAfterStr; // to use thread-safe tpGenCerts() | |
307 | } TT_KeyPairs; | |
308 | ||
309 | ||
310 | int cgVerifyInit(TestParams *testParams) | |
311 | { | |
312 | unsigned numKeys = NUM_CERTS_MIN + testParams->threadNum; | |
313 | TT_KeyPairs *keyPairs; | |
314 | ||
315 | if(testParams->verbose) { | |
316 | printf("cgVerify thread %d: generating keys...\n", | |
317 | testParams->threadNum); | |
318 | } | |
319 | keyPairs = (TT_KeyPairs *)CSSM_MALLOC(sizeof(TT_KeyPairs)); | |
320 | keyPairs->numKeys = numKeys; | |
321 | keyPairs->pubKeys = (CSSM_KEY_PTR)CSSM_CALLOC(numKeys, sizeof(CSSM_KEY)); | |
322 | keyPairs->privKeys = (CSSM_KEY_PTR)CSSM_CALLOC(numKeys, sizeof(CSSM_KEY)); | |
323 | CSSM_DL_DB_HANDLE dlDbHand = {0, 0}; | |
324 | if(tpGenKeys(testParams->cspHand, | |
325 | dlDbHand, | |
326 | numKeys, | |
327 | KEYGEN_ALG_DEF, | |
328 | CG_KEY_SIZE_DEFAULT, | |
329 | "cgVerify", // keyLabelBase | |
330 | keyPairs->pubKeys, | |
331 | keyPairs->privKeys)) { | |
332 | goto abort; | |
333 | } | |
334 | if(comparePubKeys(numKeys, keyPairs->pubKeys)) { | |
335 | return 1; | |
336 | } | |
337 | keyPairs->notBeforeStr = genTimeAtNowPlus(0); | |
338 | keyPairs->notAfterStr = genTimeAtNowPlus(SECONDS_TO_LIVE); | |
339 | ||
340 | testParams->perThread = keyPairs; | |
341 | return 0; | |
342 | ||
343 | abort: | |
344 | printf("Error generating keys; aborting\n"); | |
345 | CSSM_FREE(keyPairs->pubKeys); | |
346 | CSSM_FREE(keyPairs->privKeys); | |
347 | CSSM_FREE(keyPairs); | |
348 | return 1; | |
349 | } | |
350 | ||
351 | int cgVerify(TestParams *testParams) | |
352 | { | |
353 | unsigned loopNum; | |
354 | int status = -1; // exit status | |
355 | unsigned dex; | |
356 | ||
357 | TT_KeyPairs *keyPairs = (TT_KeyPairs *)testParams->perThread; | |
358 | ||
359 | /* all three of these are arrays with numCert elements */ | |
360 | CSSM_KEY_PTR pubKeys = keyPairs->pubKeys; | |
361 | CSSM_KEY_PTR privKeys = keyPairs->privKeys; | |
362 | CSSM_DATA_PTR certs = NULL; | |
363 | ||
364 | unsigned numCerts = keyPairs->numKeys; | |
365 | uint32 sigAlg = SIG_ALG_DEF; | |
366 | ExpectResult expectResult; | |
367 | #if CERT_IN_DB | |
368 | CSSM_BOOL useDb = CSSM_TRUE; | |
369 | #else | |
370 | CSSM_BOOL useDb = CSSM_FALSE; | |
371 | #endif | |
372 | CSSM_DL_DB_HANDLE dlDbHand = {0, 0}; | |
373 | ||
374 | /* malloc empty certs */ | |
375 | certs = (CSSM_DATA_PTR)CSSM_CALLOC(numCerts, sizeof(CSSM_DATA)); | |
376 | if(certs == NULL) { | |
377 | printf("not enough memory for %u certs.\n", numCerts); | |
378 | goto abort; | |
379 | } | |
380 | memset(certs, 0, numCerts * sizeof(CSSM_DATA)); | |
381 | ||
382 | for(loopNum=0; loopNum<testParams->numLoops; loopNum++) { | |
383 | /* generate certs */ | |
384 | if(testParams->verbose) { | |
385 | printf("generating certs...\n"); | |
386 | } | |
387 | else if(!testParams->quiet) { | |
388 | printChar(testParams->progressChar); | |
389 | } | |
390 | if(tpGenCerts(testParams->cspHand, | |
391 | testParams->clHand, | |
392 | numCerts, | |
393 | sigAlg, | |
394 | "cgConstruct", // nameBase | |
395 | pubKeys, | |
396 | privKeys, | |
397 | certs, | |
398 | keyPairs->notBeforeStr, | |
399 | keyPairs->notAfterStr)) { | |
400 | goto abort; | |
401 | } | |
402 | ||
403 | /* cycle thru test scenarios */ | |
404 | switch(loopNum % 4) { | |
405 | case 0: | |
406 | expectResult = ER_InvalidAnchor; | |
407 | break; | |
408 | case 1: | |
409 | expectResult = ER_RootInCertGroup; | |
410 | break; | |
411 | case 2: | |
412 | expectResult = ER_AnchorVerify; | |
413 | break; | |
414 | case 3: | |
415 | expectResult = ER_NoRoot; | |
416 | break; | |
417 | } | |
418 | status = doTest(testParams->tpHand, | |
419 | testParams->clHand, | |
420 | testParams->cspHand, | |
421 | dlDbHand, | |
422 | certs, | |
423 | numCerts, | |
424 | useDb, | |
425 | expectResult, | |
426 | testParams->verbose); | |
427 | if(status) { | |
428 | break; | |
429 | } | |
430 | /* free certs */ | |
431 | for(dex=0; dex<numCerts; dex++) { | |
432 | CSSM_FREE(certs[dex].Data); | |
433 | } | |
434 | memset(certs, 0, numCerts * sizeof(CSSM_DATA)); | |
435 | #if DO_PAUSE | |
436 | fpurge(stdin); | |
437 | printf("Hit CR to proceed: "); | |
438 | getchar(); | |
439 | #endif | |
440 | } | |
441 | abort: | |
442 | /* free resources */ | |
443 | for(dex=0; dex<numCerts; dex++) { | |
444 | if(certs[dex].Data) { | |
445 | CSSM_FREE(certs[dex].Data); | |
446 | } | |
447 | } | |
448 | CSSM_FREE(keyPairs->pubKeys); | |
449 | CSSM_FREE(keyPairs->privKeys); | |
450 | CSSM_FREE(keyPairs); | |
451 | return status; | |
452 | } | |
453 |