2 * Verify one CAC cert using standard system-wide cert and CRL keychains.
6 #include <security_cdsa_utils/cuFileIo.h>
7 #include <Security/cuCdsaUtils.h> /* private */
9 #include <Security/cssmerrno.h> /* private cssmErrorString() */
10 #include <Security/cssm.h>
11 #include <Security/oidsalg.h>
12 #include <Security/SecTrust.h>
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).
19 #define X509_CERT_DB "/System/Library/Keychains/X509Certificates"
20 #define X509_CRL_DB "/private/var/db/crls/crlcache.db"
22 static void usage(char **argv
)
24 printf("Usage: %s certFileName [options]\n", argv
[0]);
26 printf(" a allow unverified certs\n");
27 printf(" d disable CRL verification\n");
28 printf(" n no network fetch of CRLs\n");
32 /*** Display verify results ***/
34 static void statusBitTest(
35 CSSM_TP_APPLE_CERT_STATUS certStatus
,
39 if(certStatus
& bit
) {
44 static void printCertInfo(
45 unsigned numCerts
, // from CertGroup
46 const CSSM_TP_APPLE_EVIDENCE_INFO
*info
)
48 CSSM_TP_APPLE_CERT_STATUS cs
;
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
);
57 statusBitTest(cs
, CSSM_CERT_STATUS_EXPIRED
, "EXPIRED");
58 statusBitTest(cs
, CSSM_CERT_STATUS_NOT_VALID_YET
,
60 statusBitTest(cs
, CSSM_CERT_STATUS_IS_IN_INPUT_CERTS
,
62 statusBitTest(cs
, CSSM_CERT_STATUS_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");
71 printf(" NumStatusCodes : %u ",
72 thisInfo
->NumStatusCodes
);
73 for(unsigned j
=0; j
<thisInfo
->NumStatusCodes
; j
++) {
75 cssmErrorString(thisInfo
->StatusCodes
[j
]).c_str());
78 printf(" Index: %u\n", thisInfo
->Index
);
83 /* we really only need CSSM_EVIDENCE_FORM_APPLE_CERT_INFO */
84 #define SHOW_ALL_VFY_RESULTS 0
86 static void dumpVfyResult(
87 const CSSM_TP_VERIFY_CONTEXT_RESULT
*vfyResult
)
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
);
97 switch(ev
->EvidenceForm
) {
98 case CSSM_EVIDENCE_FORM_APPLE_HEADER
:
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
);
107 case CSSM_EVIDENCE_FORM_APPLE_CERTGROUP
:
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
);
118 case CSSM_EVIDENCE_FORM_APPLE_CERT_INFO
:
120 const CSSM_TP_APPLE_EVIDENCE_INFO
*info
=
121 (const CSSM_TP_APPLE_EVIDENCE_INFO
*)ev
->Evidence
;
122 printCertInfo(numCerts
, info
);
126 printf("***UNKNOWN Evidence form (%u)\n",
127 (unsigned)ev
->EvidenceForm
);
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
141 if(certGroup
== NULL
) {
146 /* free the individual cert Data fields */
147 for(dex
=0; dex
<certGroup
->NumCerts
; dex
++) {
148 APP_FREE(certGroup
->GroupList
.CertList
[dex
].Data
);
152 /* and the array of CSSM_DATAs */
153 if(certGroup
->GroupList
.CertList
) {
154 APP_FREE(certGroup
->GroupList
.CertList
);
164 * Free the contents of a CSSM_TP_VERIFY_CONTEXT_RESULT returned from
165 * CSSM_TP_CertGroupVerify().
167 CSSM_RETURN
freeVfyResult(
168 CSSM_TP_VERIFY_CONTEXT_RESULT
*ctx
)
171 CSSM_RETURN crtn
= CSSM_OK
;
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
;
181 case CSSM_EVIDENCE_FORM_APPLE_CERTGROUP
:
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
;
190 case CSSM_EVIDENCE_FORM_APPLE_CERT_INFO
:
192 /* Evidence = array of CSSM_TP_APPLE_EVIDENCE_INFO */
194 /* Haven't gotten a CSSM_CERTGROUP_PTR! */
195 printf("***Malformed VerifyContextResult (2)\n");
196 crtn
= CSSMERR_TP_INTERNAL_ERROR
;
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
=
205 if(thisEvInfo
->StatusCodes
) {
206 APP_FREE(thisEvInfo
->StatusCodes
);
208 if(thisEvInfo
->UniqueRecord
) {
210 CSSM_DL_FreeUniqueRecord(thisEvInfo
->DlDbHandle
,
211 thisEvInfo
->UniqueRecord
);
213 cuPrintError("CSSM_DL_FreeUniqueRecord", crtn
);
216 thisEvInfo
->UniqueRecord
= NULL
;
218 } /* for each cert info */
219 APP_FREE(evp
->Evidence
);
220 evp
->Evidence
= NULL
;
222 } /* CSSM_EVIDENCE_FORM_APPLE_CERT_INFO */
223 } /* switch(evp->EvidenceForm) */
224 } /* for each evidence */
226 APP_FREE(ctx
->Evidence
);
227 ctx
->Evidence
= NULL
;
232 static int testError(CSSM_BOOL quiet
)
237 printf("\n***Test aborting.\n");
241 printf("a to abort, c to continue: ");
243 return (resp
== 'a');
247 * The heart of CAC certification verification.
250 CSSM_TP_HANDLE tpHand
,
251 CSSM_CL_HANDLE clHand
,
252 CSSM_CSP_HANDLE cspHand
,
253 const void * certData
,
256 /* these three booleans will eventually come from system preferences */
258 bool requireFullCrlVerify
,
259 bool enableFetchFromNet
,
260 CSSM_DL_DB_HANDLE_PTR certKeychain
,
261 CSSM_DL_DB_HANDLE_PTR crlKeychain
)
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
;
268 memset(&vfyCtx
, 0, sizeof(CSSM_TP_VERIFY_CONTEXT
));
269 memset(&authCtx
, 0, sizeof(CSSM_TP_CALLERAUTH_CONTEXT
));
271 /* CSSM_TP_CALLERAUTH_CONTEXT components */
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;
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;
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
;
299 if(enableFetchFromNet
) {
300 crlOpts
.CrlFlags
|= CSSM_TP_ACTION_FETCH_CRL_FROM_NET
;
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
306 crlOpts
.crlStore
= crlKeychain
;
308 authCtx
.Policy
.NumberOfPolicyIds
= 2;
311 /* No CRL checking */
312 authCtx
.Policy
.NumberOfPolicyIds
= 1;
314 authCtx
.Policy
.PolicyIds
= policyIds
;
315 authCtx
.Policy
.PolicyControl
= NULL
;
317 authCtx
.VerifyTime
= NULL
;
318 authCtx
.VerificationAbortOn
= CSSM_TP_STOP_ON_POLICY
;
319 authCtx
.CallbackWithVerifiedCert
= NULL
;
322 const CSSM_DATA
*anchors
;
325 ortn
= SecTrustGetCSSMAnchorCertificates(&anchors
, &anchorCount
);
327 printf("SecTrustGetCSSMAnchorCertificates returned %u\n", ortn
);
330 authCtx
.NumberOfAnchorCerts
= anchorCount
;
331 authCtx
.AnchorCerts
= const_cast<CSSM_DATA_PTR
>(anchors
);
333 /* DBList of intermediate certs and CRLs */
334 CSSM_DL_DB_HANDLE handles
[2];
336 if(certKeychain
!= NULL
) {
337 handles
[0] = *certKeychain
;
340 if(crlKeychain
!= NULL
) {
341 handles
[numDbs
] = *crlKeychain
;
344 CSSM_DL_DB_LIST dlDbList
;
345 dlDbList
.NumHandles
= numDbs
;
346 dlDbList
.DLDBHandle
= &handles
[0];
348 authCtx
.DBList
= &dlDbList
;
349 authCtx
.CallerCredentials
= NULL
;
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
;
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;
363 cert
.Data
= (uint8
*)certData
;
364 cert
.Length
= certLength
;
365 cssmCerts
.GroupList
.CertList
= &cert
;
366 cssmCerts
.CertGroupType
= CSSM_CERTGROUP_DATA
;
368 CSSM_RETURN crtn
= CSSM_TP_CertGroupVerify(tpHand
,
375 cuPrintError("CSSM_TP_CertGroupVerify", crtn
);
378 printf("...verify successful\n");
380 dumpVfyResult(&vfyResult
);
381 freeVfyResult(&vfyResult
);
390 int main(int argc
, char **argv
)
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
;
404 bool requireFullCrlVerify
= true;
405 bool enableFetchFromNet
= true;
406 bool enableCrlCheck
= true;
413 for(arg
=2; arg
<argc
; arg
++) {
417 requireFullCrlVerify
= false;
420 enableCrlCheck
= false;
423 enableFetchFromNet
= false;
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();
437 rtn
= readFile(argv
[1], &certData
, &certLength
);
439 printf("***Error reading cert file %s\n", argv
[1]);
443 /* get the intermediate certs */
444 crtn
= CSSM_DL_DbOpen(dlHand
,
448 NULL
, // CSSM_ACCESS_CREDENTIALS *AccessCred
449 NULL
, // void *OpenParameters
450 &certKeychain
.DBHandle
);
452 cuPrintError("CSSM_DL_DbOpen", crtn
);
453 printf("***Error opening intermediate cert file %s. This op will"
454 "probably fail.n", X509_CERT_DB
);
457 certKeychain
.DLHandle
= dlHand
;
458 certKeychainPtr
= &certKeychain
;
461 /* and the CRL cache */
462 crtn
= CSSM_DL_DbOpen(dlHand
,
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
;
475 vfyCert(tpHand
, clHand
, cspHand
, certData
, certLength
,
476 enableCrlCheck
, requireFullCrlVerify
, enableFetchFromNet
,
477 certKeychainPtr
, crlKeychainPtr
);
479 /* Cleanup - release handles, free certData, etc. */
481 if(crlKeychainPtr
!= NULL
) {
482 CSSM_DL_DbClose(crlKeychain
);
484 if(certKeychainPtr
!= NULL
) {
485 CSSM_DL_DbClose(certKeychain
);
487 CSSM_ModuleDetach(dlHand
);
488 CSSM_ModuleDetach(clHand
);
489 CSSM_ModuleDetach(tpHand
);
490 CSSM_ModuleDetach(cspHand
);