]> git.saurik.com Git - apple/security.git/blob - SecurityTests/clxutils/vfyCacCert/vfyCacCert.cpp
Security-57336.1.9.tar.gz
[apple/security.git] / SecurityTests / clxutils / vfyCacCert / vfyCacCert.cpp
1 /*
2 * Verify one CAC cert using standard system-wide cert and CRL keychains.
3 */
4 #include <stdlib.h>
5 #include <stdio.h>
6 #include <security_cdsa_utils/cuFileIo.h>
7 #include <Security/cuCdsaUtils.h> /* private */
8 //#include "clutils.h"
9 #include <Security/cssmerrno.h> /* private cssmErrorString() */
10 #include <Security/cssm.h>
11 #include <Security/oidsalg.h>
12 #include <Security/SecTrust.h>
13
14 /*
15 * More-or-less hard-coded locations of system-wide keychains containing
16 * intermediate certs (which are required for this operation) and
17 * CRLs (which is optional; it's just a cache for performance reasons).
18 */
19 #define X509_CERT_DB "/System/Library/Keychains/X509Certificates"
20 #define X509_CRL_DB "/private/var/db/crls/crlcache.db"
21
22 static void usage(char **argv)
23 {
24 printf("Usage: %s certFileName [options]\n", argv[0]);
25 printf("Options:\n");
26 printf(" a allow unverified certs\n");
27 printf(" d disable CRL verification\n");
28 printf(" n no network fetch of CRLs\n");
29 exit(1);
30 }
31
32 /*** Display verify results ***/
33
34 static void statusBitTest(
35 CSSM_TP_APPLE_CERT_STATUS certStatus,
36 uint32 bit,
37 const char *str)
38 {
39 if(certStatus & bit) {
40 printf("%s ", str);
41 }
42 }
43
44 static void printCertInfo(
45 unsigned numCerts, // from CertGroup
46 const CSSM_TP_APPLE_EVIDENCE_INFO *info)
47 {
48 CSSM_TP_APPLE_CERT_STATUS cs;
49
50 for(unsigned i=0; i<numCerts; i++) {
51 const CSSM_TP_APPLE_EVIDENCE_INFO *thisInfo = &info[i];
52 cs = thisInfo->StatusBits;
53 printf(" cert %u:\n", i);
54 printf(" StatusBits : 0x%x", (unsigned)cs);
55 if(cs) {
56 printf(" ( ");
57 statusBitTest(cs, CSSM_CERT_STATUS_EXPIRED, "EXPIRED");
58 statusBitTest(cs, CSSM_CERT_STATUS_NOT_VALID_YET,
59 "NOT_VALID_YET");
60 statusBitTest(cs, CSSM_CERT_STATUS_IS_IN_INPUT_CERTS,
61 "IS_IN_INPUT_CERTS");
62 statusBitTest(cs, CSSM_CERT_STATUS_IS_IN_ANCHORS,
63 "IS_IN_ANCHORS");
64 statusBitTest(cs, CSSM_CERT_STATUS_IS_ROOT, "IS_ROOT");
65 statusBitTest(cs, CSSM_CERT_STATUS_IS_FROM_NET, "IS_FROM_NET");
66 printf(")\n");
67 }
68 else {
69 printf("\n");
70 }
71 printf(" NumStatusCodes : %u ",
72 thisInfo->NumStatusCodes);
73 for(unsigned j=0; j<thisInfo->NumStatusCodes; j++) {
74 printf("%s ",
75 cssmErrorString(thisInfo->StatusCodes[j]).c_str());
76 }
77 printf("\n");
78 printf(" Index: %u\n", thisInfo->Index);
79 }
80 return;
81 }
82
83 /* we really only need CSSM_EVIDENCE_FORM_APPLE_CERT_INFO */
84 #define SHOW_ALL_VFY_RESULTS 0
85
86 static void dumpVfyResult(
87 const CSSM_TP_VERIFY_CONTEXT_RESULT *vfyResult)
88 {
89 unsigned numEvidences = vfyResult->NumberOfEvidences;
90 unsigned numCerts = 0;
91 printf("Returned evidence:\n");
92 for(unsigned dex=0; dex<numEvidences; dex++) {
93 CSSM_EVIDENCE_PTR ev = &vfyResult->Evidence[dex];
94 #if SHOW_ALL_VFY_RESULTS
95 printf(" Evidence %u:\n", dex);
96 #endif
97 switch(ev->EvidenceForm) {
98 case CSSM_EVIDENCE_FORM_APPLE_HEADER:
99 {
100 #if SHOW_ALL_VFY_RESULTS
101 const CSSM_TP_APPLE_EVIDENCE_HEADER *hdr =
102 (const CSSM_TP_APPLE_EVIDENCE_HEADER *)(ev->Evidence);
103 printf(" Form = HEADER; Version = %u\n", hdr->Version);
104 #endif
105 break;
106 }
107 case CSSM_EVIDENCE_FORM_APPLE_CERTGROUP:
108 {
109 const CSSM_CERTGROUP *grp = (const CSSM_CERTGROUP *)ev->Evidence;
110 numCerts = grp->NumCerts;
111 #if SHOW_ALL_VFY_RESULTS
112 /* parse the rest of this eventually */
113 /* Note we depend on this coming before the CERT_INFO */
114 printf(" Form = CERTGROUP; numCerts = %u\n", numCerts);
115 #endif
116 break;
117 }
118 case CSSM_EVIDENCE_FORM_APPLE_CERT_INFO:
119 {
120 const CSSM_TP_APPLE_EVIDENCE_INFO *info =
121 (const CSSM_TP_APPLE_EVIDENCE_INFO *)ev->Evidence;
122 printCertInfo(numCerts, info);
123 break;
124 }
125 default:
126 printf("***UNKNOWN Evidence form (%u)\n",
127 (unsigned)ev->EvidenceForm);
128 break;
129 }
130 }
131 }
132
133 /* free a CSSM_CERT_GROUP */
134 void tpFreeCertGroup(
135 CSSM_CERTGROUP_PTR certGroup,
136 CSSM_BOOL freeCertData, // free individual CertList.Data
137 CSSM_BOOL freeStruct) // free the overall CSSM_CERTGROUP
138 {
139 unsigned dex;
140
141 if(certGroup == NULL) {
142 return;
143 }
144
145 if(freeCertData) {
146 /* free the individual cert Data fields */
147 for(dex=0; dex<certGroup->NumCerts; dex++) {
148 APP_FREE(certGroup->GroupList.CertList[dex].Data);
149 }
150 }
151
152 /* and the array of CSSM_DATAs */
153 if(certGroup->GroupList.CertList) {
154 APP_FREE(certGroup->GroupList.CertList);
155 }
156
157 if(freeStruct) {
158 APP_FREE(certGroup);
159 }
160 }
161
162
163 /*
164 * Free the contents of a CSSM_TP_VERIFY_CONTEXT_RESULT returned from
165 * CSSM_TP_CertGroupVerify().
166 */
167 CSSM_RETURN freeVfyResult(
168 CSSM_TP_VERIFY_CONTEXT_RESULT *ctx)
169 {
170 int numCerts = -1;
171 CSSM_RETURN crtn = CSSM_OK;
172
173 for(unsigned i=0; i<ctx->NumberOfEvidences; i++) {
174 CSSM_EVIDENCE_PTR evp = &ctx->Evidence[i];
175 switch(evp->EvidenceForm) {
176 case CSSM_EVIDENCE_FORM_APPLE_HEADER:
177 /* Evidence = (CSSM_TP_APPLE_EVIDENCE_HEADER *) */
178 APP_FREE(evp->Evidence);
179 evp->Evidence = NULL;
180 break;
181 case CSSM_EVIDENCE_FORM_APPLE_CERTGROUP:
182 {
183 /* Evidence = CSSM_CERTGROUP_PTR */
184 CSSM_CERTGROUP_PTR cgp = (CSSM_CERTGROUP_PTR)evp->Evidence;
185 numCerts = cgp->NumCerts;
186 tpFreeCertGroup(cgp, CSSM_TRUE, CSSM_TRUE);
187 evp->Evidence = NULL;
188 break;
189 }
190 case CSSM_EVIDENCE_FORM_APPLE_CERT_INFO:
191 {
192 /* Evidence = array of CSSM_TP_APPLE_EVIDENCE_INFO */
193 if(numCerts < 0) {
194 /* Haven't gotten a CSSM_CERTGROUP_PTR! */
195 printf("***Malformed VerifyContextResult (2)\n");
196 crtn = CSSMERR_TP_INTERNAL_ERROR;
197 break;
198 }
199 CSSM_TP_APPLE_EVIDENCE_INFO *evInfo =
200 (CSSM_TP_APPLE_EVIDENCE_INFO *)evp->Evidence;
201 for(unsigned k=0; k<(unsigned)numCerts; k++) {
202 /* Dispose of StatusCodes, UniqueRecord */
203 CSSM_TP_APPLE_EVIDENCE_INFO *thisEvInfo =
204 &evInfo[k];
205 if(thisEvInfo->StatusCodes) {
206 APP_FREE(thisEvInfo->StatusCodes);
207 }
208 if(thisEvInfo->UniqueRecord) {
209 CSSM_RETURN crtn =
210 CSSM_DL_FreeUniqueRecord(thisEvInfo->DlDbHandle,
211 thisEvInfo->UniqueRecord);
212 if(crtn) {
213 cuPrintError("CSSM_DL_FreeUniqueRecord", crtn);
214 break;
215 }
216 thisEvInfo->UniqueRecord = NULL;
217 }
218 } /* for each cert info */
219 APP_FREE(evp->Evidence);
220 evp->Evidence = NULL;
221 break;
222 } /* CSSM_EVIDENCE_FORM_APPLE_CERT_INFO */
223 } /* switch(evp->EvidenceForm) */
224 } /* for each evidence */
225 if(ctx->Evidence) {
226 APP_FREE(ctx->Evidence);
227 ctx->Evidence = NULL;
228 }
229 return crtn;
230 }
231
232 static int testError(CSSM_BOOL quiet)
233 {
234 char resp;
235
236 if(quiet) {
237 printf("\n***Test aborting.\n");
238 exit(1);
239 }
240 fpurge(stdin);
241 printf("a to abort, c to continue: ");
242 resp = getchar();
243 return (resp == 'a');
244 }
245
246 /*
247 * The heart of CAC certification verification.
248 */
249 int vfyCert(
250 CSSM_TP_HANDLE tpHand,
251 CSSM_CL_HANDLE clHand,
252 CSSM_CSP_HANDLE cspHand,
253 const void * certData,
254 unsigned certLength,
255
256 /* these three booleans will eventually come from system preferences */
257 bool enableCrlCheck,
258 bool requireFullCrlVerify,
259 bool enableFetchFromNet,
260 CSSM_DL_DB_HANDLE_PTR certKeychain,
261 CSSM_DL_DB_HANDLE_PTR crlKeychain)
262 {
263 /* main job is building a CSSM_TP_VERIFY_CONTEXT and its components */
264 CSSM_TP_VERIFY_CONTEXT vfyCtx;
265 CSSM_TP_CALLERAUTH_CONTEXT authCtx;
266 CSSM_TP_VERIFY_CONTEXT_RESULT vfyResult;
267
268 memset(&vfyCtx, 0, sizeof(CSSM_TP_VERIFY_CONTEXT));
269 memset(&authCtx, 0, sizeof(CSSM_TP_CALLERAUTH_CONTEXT));
270
271 /* CSSM_TP_CALLERAUTH_CONTEXT components */
272 /*
273 typedef struct cssm_tp_callerauth_context {
274 CSSM_TP_POLICYINFO Policy;
275 CSSM_TIMESTRING VerifyTime;
276 CSSM_TP_STOP_ON VerificationAbortOn;
277 CSSM_TP_VERIFICATION_RESULTS_CALLBACK CallbackWithVerifiedCert;
278 uint32 NumberOfAnchorCerts;
279 CSSM_DATA_PTR AnchorCerts;
280 CSSM_DL_DB_LIST_PTR DBList;
281 CSSM_ACCESS_CREDENTIALS_PTR CallerCredentials;
282 } CSSM_TP_CALLERAUTH_CONTEXT, *CSSM_TP_CALLERAUTH_CONTEXT_PTR;
283 */
284 /* two policies */
285 CSSM_FIELD policyIds[2];
286 CSSM_APPLE_TP_CRL_OPTIONS crlOpts;
287 policyIds[0].FieldOid = CSSMOID_APPLE_X509_BASIC;
288 policyIds[0].FieldValue.Data = NULL;
289 policyIds[0].FieldValue.Length = 0;
290 if(enableCrlCheck) {
291 policyIds[1].FieldOid = CSSMOID_APPLE_TP_REVOCATION_CRL;
292 policyIds[1].FieldValue.Data = (uint8 *)&crlOpts;
293 policyIds[1].FieldValue.Length = sizeof(crlOpts);
294 crlOpts.Version = CSSM_APPLE_TP_CRL_OPTS_VERSION;
295 crlOpts.CrlFlags = 0;
296 if(requireFullCrlVerify) {
297 crlOpts.CrlFlags |= CSSM_TP_ACTION_REQUIRE_CRL_PER_CERT;
298 }
299 if(enableFetchFromNet) {
300 crlOpts.CrlFlags |= CSSM_TP_ACTION_FETCH_CRL_FROM_NET;
301 }
302 /* optional, may well not exist */
303 /* FIXME: as of 12/4/02 this field is ignored by the TP
304 * and may well go away from the CSSM_APPLE_TP_CRL_OPTIONS
305 * struct. */
306 crlOpts.crlStore = crlKeychain;
307
308 authCtx.Policy.NumberOfPolicyIds = 2;
309 }
310 else {
311 /* No CRL checking */
312 authCtx.Policy.NumberOfPolicyIds = 1;
313 }
314 authCtx.Policy.PolicyIds = policyIds;
315 authCtx.Policy.PolicyControl = NULL;
316
317 authCtx.VerifyTime = NULL;
318 authCtx.VerificationAbortOn = CSSM_TP_STOP_ON_POLICY;
319 authCtx.CallbackWithVerifiedCert = NULL;
320
321 /* anchors */
322 const CSSM_DATA *anchors;
323 uint32 anchorCount;
324 OSStatus ortn;
325 ortn = SecTrustGetCSSMAnchorCertificates(&anchors, &anchorCount);
326 if(ortn) {
327 printf("SecTrustGetCSSMAnchorCertificates returned %u\n", ortn);
328 return -1;
329 }
330 authCtx.NumberOfAnchorCerts = anchorCount;
331 authCtx.AnchorCerts = const_cast<CSSM_DATA_PTR>(anchors);
332
333 /* DBList of intermediate certs and CRLs */
334 CSSM_DL_DB_HANDLE handles[2];
335 unsigned numDbs = 0;
336 if(certKeychain != NULL) {
337 handles[0] = *certKeychain;
338 numDbs++;
339 }
340 if(crlKeychain != NULL) {
341 handles[numDbs] = *crlKeychain;
342 numDbs++;
343 }
344 CSSM_DL_DB_LIST dlDbList;
345 dlDbList.NumHandles = numDbs;
346 dlDbList.DLDBHandle = &handles[0];
347
348 authCtx.DBList = &dlDbList;
349 authCtx.CallerCredentials = NULL;
350
351 /* CSSM_TP_VERIFY_CONTEXT */
352 vfyCtx.ActionData.Data = NULL;
353 vfyCtx.ActionData.Length = 0;
354 vfyCtx.Action = CSSM_TP_ACTION_DEFAULT;
355 vfyCtx.Cred = &authCtx;
356
357 /* cook up cert group */
358 CSSM_CERTGROUP cssmCerts;
359 cssmCerts.CertType = CSSM_CERT_X_509v3;
360 cssmCerts.CertEncoding = CSSM_CERT_ENCODING_DER;
361 cssmCerts.NumCerts = 1;
362 CSSM_DATA cert;
363 cert.Data = (uint8 *)certData;
364 cert.Length = certLength;
365 cssmCerts.GroupList.CertList = &cert;
366 cssmCerts.CertGroupType = CSSM_CERTGROUP_DATA;
367
368 CSSM_RETURN crtn = CSSM_TP_CertGroupVerify(tpHand,
369 clHand,
370 cspHand,
371 &cssmCerts,
372 &vfyCtx,
373 &vfyResult);
374 if(crtn) {
375 cuPrintError("CSSM_TP_CertGroupVerify", crtn);
376 }
377 else {
378 printf("...verify successful\n");
379 }
380 dumpVfyResult(&vfyResult);
381 freeVfyResult(&vfyResult);
382 if(crtn) {
383 return testError(0);
384 }
385 else {
386 return 0;
387 }
388 }
389
390 int main(int argc, char **argv)
391 {
392 int rtn;
393 CSSM_RETURN crtn;
394 CSSM_DL_HANDLE dlHand;
395 CSSM_CSP_HANDLE cspHand;
396 CSSM_CL_HANDLE clHand;
397 CSSM_TP_HANDLE tpHand;
398 CSSM_DL_DB_HANDLE certKeychain;
399 CSSM_DL_DB_HANDLE crlKeychain;
400 CSSM_DL_DB_HANDLE_PTR certKeychainPtr = NULL;
401 CSSM_DL_DB_HANDLE_PTR crlKeychainPtr = NULL;
402 unsigned char *certData;
403 unsigned certLength;
404 bool requireFullCrlVerify = true;
405 bool enableFetchFromNet = true;
406 bool enableCrlCheck = true;
407 int arg;
408 char *argp;
409
410 if(argc < 2) {
411 usage(argv);
412 }
413 for(arg=2; arg<argc; arg++) {
414 argp = argv[arg];
415 switch(argp[0]) {
416 case 'a':
417 requireFullCrlVerify = false;
418 break;
419 case 'd':
420 enableCrlCheck = false;
421 break;
422 case 'n':
423 enableFetchFromNet = false;
424 break;
425 default:
426 usage(argv);
427 }
428 }
429
430 /* in the real world all these should be verified to be nonzero */
431 cspHand = cuCspStartup(CSSM_TRUE);
432 clHand = cuClStartup();
433 tpHand = cuTpStartup();
434 dlHand = cuDlStartup();
435
436 /* get the cert */
437 rtn = readFile(argv[1], &certData, &certLength);
438 if(rtn) {
439 printf("***Error reading cert file %s\n", argv[1]);
440 exit(1);
441 }
442
443 /* get the intermediate certs */
444 crtn = CSSM_DL_DbOpen(dlHand,
445 X509_CERT_DB,
446 NULL, // DbLocation
447 CSSM_DB_ACCESS_READ,
448 NULL, // CSSM_ACCESS_CREDENTIALS *AccessCred
449 NULL, // void *OpenParameters
450 &certKeychain.DBHandle);
451 if(crtn) {
452 cuPrintError("CSSM_DL_DbOpen", crtn);
453 printf("***Error opening intermediate cert file %s. This op will"
454 "probably fail.n", X509_CERT_DB);
455 }
456 else {
457 certKeychain.DLHandle = dlHand;
458 certKeychainPtr = &certKeychain;
459 }
460
461 /* and the CRL cache */
462 crtn = CSSM_DL_DbOpen(dlHand,
463 X509_CRL_DB,
464 NULL, // DbLocation
465 CSSM_DB_ACCESS_READ,
466 NULL, // CSSM_ACCESS_CREDENTIALS *AccessCred
467 NULL, // void *OpenParameters
468 &crlKeychain.DBHandle);
469 if(crtn == CSSM_OK) {
470 crlKeychain.DLHandle = dlHand;
471 crlKeychainPtr = &crlKeychain;
472 }
473
474 /* go for it */
475 vfyCert(tpHand, clHand, cspHand, certData, certLength,
476 enableCrlCheck, requireFullCrlVerify, enableFetchFromNet,
477 certKeychainPtr, crlKeychainPtr);
478
479 /* Cleanup - release handles, free certData, etc. */
480 free(certData);
481 if(crlKeychainPtr != NULL) {
482 CSSM_DL_DbClose(crlKeychain);
483 }
484 if(certKeychainPtr != NULL) {
485 CSSM_DL_DbClose(certKeychain);
486 }
487 CSSM_ModuleDetach(dlHand);
488 CSSM_ModuleDetach(clHand);
489 CSSM_ModuleDetach(tpHand);
490 CSSM_ModuleDetach(cspHand);
491
492 return 0;
493
494 }