1/*
2 * certVerify.cpp - execute cert/CRL verify; display results
3 */
4
5#include "certVerify.h"
6#include "tpUtils.h"
7#include <utilLib/common.h>
8#include <clAppUtils/clutils.h>
9#include <clAppUtils/tpUtils.h>
10#include <stdlib.h>
11#include <stdio.h>
12#include <string.h>
13#include <Security/cssm.h>
14#include <Security/oidsalg.h>
15#include <Security/SecTrust.h>
16#include <Security/SecPolicySearch.h>
17#include <Security/cssmapplePriv.h>
18#include <security_cdsa_utils/cuCdsaUtils.h>
19#include <Security/TrustSettingsSchema.h>
20
21static int vfyCertErrors(
22	const CSSM_TP_VERIFY_CONTEXT_RESULT *vfyResult,
23	unsigned numCertErrors,
24	const char **certErrors,	// e.g., "2:CSSMERR_TP_CERT_EXPIRED"
25	CSSM_BOOL quiet)
26{
27	if(numCertErrors == 0) {
28		return 0;
29	}
30	if(vfyResult->NumberOfEvidences != 3) {
31		printf("***vfyCertErrors: NumberOfEvidences is %u, expect 3\n",
32			(unsigned)vfyResult->NumberOfEvidences);
33		return 1;
34	}
35
36	/* numCerts from evidence[1] */
37	const CSSM_EVIDENCE *ev = &vfyResult->Evidence[1];
38	const CSSM_CERTGROUP *grp = (const CSSM_CERTGROUP *)ev->Evidence;
39	unsigned numCerts = grp->NumCerts;
40	/* array of Apple-specific info from evidence[2] */
41	ev = &vfyResult->Evidence[2];
42	const CSSM_TP_APPLE_EVIDENCE_INFO *info =
43				(const CSSM_TP_APPLE_EVIDENCE_INFO *)ev->Evidence;
44	int ourRtn = 0;
45
46	for(unsigned dex=0; dex<numCertErrors; dex++) {
47		const char *str = certErrors[dex];
48		char buf[8];
49		unsigned i;
50
51		/*
52		 * Format is certNum:errorString
53		 * first get the cert number
54		 */
55		for(i=0; *str != '\0'; i++, str++) {
56			if(*str == ':') {
57				break;
58			}
59			buf[i] = *str;
60		}
61		if(*str != ':') {
62			printf("***Bad certerror value, format is certNum:errorString\n");
63			return 1;
64		}
65		buf[i] = '\0';
66		unsigned certNum = atoi(buf);
67		if(certNum > (numCerts-1)) {
68			printf("***certerror specified for cert %u, but only %u certs"
69				" available\n", certNum, numCerts);
70			return 1;
71		}
72		str++;			// pts to actual desired error string now
73
74		/*
75		 * There may be multiple per-cert statuses in the evidence; search all
76		 * looking for a match
77		 */
78		const CSSM_TP_APPLE_EVIDENCE_INFO *thisInfo = &info[certNum];
79		char *found = NULL;
80		for(unsigned i=0; i<thisInfo->NumStatusCodes; i++) {
81			CSSM_RETURN actRtn = thisInfo->StatusCodes[i];
82			const char *actRtnStr = cssmErrToStr(actRtn);
83			found = strstr(actRtnStr, str);
84			if(found) {
85				break;
86			}
87		}
88		if(found) {
89			if(!quiet) {
90				printf("...%s per-cert status received as expected\n", str);
91			}
92		}
93		else {
94			printf("***Per cert status %s not found\n", str);
95			ourRtn = 1;
96			/* might as well keep going */
97		}
98	}
99	return ourRtn;
100}
101
102static int vfyCertStatus(
103	const CSSM_TP_VERIFY_CONTEXT_RESULT *vfyResult,
104	unsigned numCertStatus,
105	const char **certStatus,	// e.g., "1:0x18", leading 0x optional
106	CSSM_BOOL quiet)
107{
108	if(numCertStatus == 0) {
109		return 0;
110	}
111	if(vfyResult->NumberOfEvidences != 3) {
112		printf("***vfyCertStatus: NumberOfEvidences is %u, expect 3\n",
113			(unsigned)vfyResult->NumberOfEvidences);
114		return 1;
115	}
116
117	/* numCerts from evidence[1] */
118	const CSSM_EVIDENCE *ev = &vfyResult->Evidence[1];
119	const CSSM_CERTGROUP *grp = (const CSSM_CERTGROUP *)ev->Evidence;
120	unsigned numCerts = grp->NumCerts;
121	/* array of Apple-specific info from evidence[2] */
122	ev = &vfyResult->Evidence[2];
123	const CSSM_TP_APPLE_EVIDENCE_INFO *info =
124				(const CSSM_TP_APPLE_EVIDENCE_INFO *)ev->Evidence;
125	int ourRtn = 0;
126
127	for(unsigned dex=0; dex<numCertStatus; dex++) {
128		const char *str = certStatus[dex];
129		char buf[8];
130		unsigned i;
131
132		/*
133		 * Format is certNum:status_in_hex
134		 * first get the cert number
135		 */
136		for(i=0; *str != '\0'; i++, str++) {
137			if(*str == ':') {
138				break;
139			}
140			buf[i] = *str;
141		}
142		if(*str != ':') {
143			printf("***Bad certstatus value, format is certNum:status_in_hex\n");
144			return 1;
145		}
146		buf[i] = '\0';
147		unsigned certNum = atoi(buf);
148		if(certNum > (numCerts-1)) {
149			printf("***certerror specified for cert %u, but only %u certs"
150				" available\n", certNum, numCerts);
151			return 1;
152		}
153		str++;			// pts to actual desired status string now
154		unsigned certStat = hexToBin(str);
155		const CSSM_TP_APPLE_EVIDENCE_INFO *thisInfo = &info[certNum];
156		if(certStat == thisInfo->StatusBits) {
157			if(!quiet) {
158				printf("...0x%x per-cert status received as expected\n", certStat);
159			}
160		}
161		else {
162			printf("***Expected per cert status 0x%x, got 0x%x\n",
163				(unsigned)certStat, (unsigned)thisInfo->StatusBits);
164			ourRtn = 1;
165		}
166	}
167	return ourRtn;
168}
169
170/*
171 * Ensure that the policy being evaluated is accessible via
172 * SecPolicySearch*(). Not really part of the test, but a handy place
173 * to catch this common error before checking in TP changes.
174 */
175static int verifySecPolicy(
176	const CSSM_OID *oid)
177{
178	SecPolicySearchRef srchRef = NULL;
179	OSStatus ortn;
180
181	ortn = SecPolicySearchCreate(CSSM_CERT_X_509v3, oid, NULL, &srchRef);
182	if(ortn) {
183		cssmPerror("SecPolicySearchCreate", ortn);
184		return -1;
185	}
186	SecPolicyRef policyRef = NULL;
187	ortn = SecPolicySearchCopyNext(srchRef, &policyRef);
188	if(ortn) {
189		cssmPerror("SecPolicySearchCopyNext", ortn);
190		printf("***The TP policy used in this test is not accessible via SecPolicySearchCopyNext().\n");
191		printf("   You probably forgot to add the policy to the theOidList table in PolicyCursor.cpp\n");
192		printf("   in the libsecurity_keychain project.\n");
193	}
194	CFRelease(srchRef);
195	if(policyRef) {
196		CFRelease(policyRef);
197	}
198	return ortn;
199}
200
201int certVerify(CertVerifyArgs *vfyArgs)
202{
203	if(vfyArgs->version != CERT_VFY_ARGS_VERS) {
204		printf("***CertVerifyArgs.Version mismatch. Clean and rebuild.\n");
205		return -1;
206	}
207
208	/* main job is building a CSSM_TP_VERIFY_CONTEXT and its components */
209	CSSM_TP_VERIFY_CONTEXT			vfyCtx;
210	CSSM_TP_CALLERAUTH_CONTEXT		authCtx;
211	CSSM_TP_VERIFY_CONTEXT_RESULT	vfyResult;
212	CSSM_APPLE_TP_SSL_OPTIONS		sslOpts;
213	CSSM_APPLE_TP_SMIME_OPTIONS		smimeOpts;
214
215	memset(&vfyCtx, 0, sizeof(CSSM_TP_VERIFY_CONTEXT));
216	memset(&authCtx, 0, sizeof(CSSM_TP_CALLERAUTH_CONTEXT));
217
218	/* CSSM_TP_CALLERAUTH_CONTEXT components */
219	/*
220		typedef struct cssm_tp_callerauth_context {
221			CSSM_TP_POLICYINFO Policy;
222			CSSM_TIMESTRING VerifyTime;
223			CSSM_TP_STOP_ON VerificationAbortOn;
224			CSSM_TP_VERIFICATION_RESULTS_CALLBACK CallbackWithVerifiedCert;
225			uint32 NumberOfAnchorCerts;
226			CSSM_DATA_PTR AnchorCerts;
227			CSSM_DL_DB_LIST_PTR DBList;
228			CSSM_ACCESS_CREDENTIALS_PTR CallerCredentials;
229		} CSSM_TP_CALLERAUTH_CONTEXT, *CSSM_TP_CALLERAUTH_CONTEXT_PTR;
230	*/
231	/* up to 3 policies */
232	CSSM_FIELD	policyIds[3];
233	CSSM_FIELD  *policyPtr = &policyIds[0];
234	uint32 numPolicies = 0;
235	memset(policyIds, 0, 3 * sizeof(CSSM_FIELD));
236
237	switch(vfyArgs->vfyPolicy) {
238		case CVP_SSL:
239		case CVP_IPSec:
240			if(vfyArgs->vfyPolicy == CVP_SSL) {
241				policyPtr->FieldOid = CSSMOID_APPLE_TP_SSL;
242			}
243			else {
244				policyPtr->FieldOid = CSSMOID_APPLE_TP_IP_SEC;
245			}
246			/* otherwise these policies are identical */
247			/* sslOpts is optional */
248			if((vfyArgs->sslHost != NULL) || vfyArgs->sslClient) {
249				memset(&sslOpts, 0, sizeof(sslOpts));
250				sslOpts.Version = CSSM_APPLE_TP_SSL_OPTS_VERSION;
251				sslOpts.ServerName = vfyArgs->sslHost;
252				if(vfyArgs->sslHost != NULL) {
253					sslOpts.ServerNameLen = strlen(vfyArgs->sslHost) + 1;
254				}
255				if(vfyArgs->sslClient) {
256					sslOpts.Flags |= CSSM_APPLE_TP_SSL_CLIENT;
257				}
258				policyPtr->FieldValue.Data = (uint8 *)&sslOpts;
259				policyPtr->FieldValue.Length = sizeof(sslOpts);
260			}
261			break;
262		case CVP_SMIME:
263		case CVP_iChat:
264			if(vfyArgs->vfyPolicy == CVP_SMIME) {
265				policyPtr->FieldOid = CSSMOID_APPLE_TP_SMIME;
266			}
267			else {
268				policyPtr->FieldOid = CSSMOID_APPLE_TP_ICHAT;
269			}
270			/* otherwise these policies are identical */
271			/* smimeOpts is optional */
272			if(vfyArgs->senderEmail != NULL) {
273				smimeOpts.Version = CSSM_APPLE_TP_SMIME_OPTS_VERSION;
274				smimeOpts.IntendedUsage = vfyArgs->intendedKeyUse;
275				smimeOpts.SenderEmail = vfyArgs->senderEmail;
276				smimeOpts.SenderEmailLen = strlen(vfyArgs->senderEmail) + 1;
277				policyPtr->FieldValue.Data = (uint8 *)&smimeOpts;
278				policyPtr->FieldValue.Length = sizeof(smimeOpts);
279			}
280			break;
281		case CVP_Basic:
282			policyPtr->FieldOid = CSSMOID_APPLE_X509_BASIC;
283			break;
284		case CVP_SWUpdateSign:
285			/* no options */
286			policyPtr->FieldOid = CSSMOID_APPLE_TP_SW_UPDATE_SIGNING;
287			break;
288		case CVP_ResourceSigning:
289			/* no options */
290			policyPtr->FieldOid = CSSMOID_APPLE_TP_RESOURCE_SIGN;
291			break;
292		case CVP_PKINIT_Server:
293			/* no options */
294			policyPtr->FieldOid = CSSMOID_APPLE_TP_PKINIT_SERVER;
295			break;
296		case CVP_PKINIT_Client:
297			/* no options */
298			policyPtr->FieldOid = CSSMOID_APPLE_TP_PKINIT_CLIENT;
299			break;
300		case CVP_AppleCodeSigning:
301			/* no options */
302			policyPtr->FieldOid = CSSMOID_APPLE_TP_CODE_SIGNING;
303			break;
304		case CVP_PackageSigning:
305			/* no options */
306			policyPtr->FieldOid = CSSMOID_APPLE_TP_PACKAGE_SIGNING;
307			break;
308		default:
309			printf("***certVerify: bogus vfyPolicy\n");
310			return 1;
311	}
312	if(verifySecPolicy(&policyPtr->FieldOid)) {
313		return -1;
314	}
315	policyPtr++;
316	numPolicies++;
317
318	CSSM_APPLE_TP_CRL_OPTIONS crlOpts;
319	if((vfyArgs->revokePolicy == CRP_CRL) || (vfyArgs->revokePolicy == CRP_CRL_OCSP)) {
320		memset(&crlOpts, 0, sizeof(crlOpts));
321		policyPtr->FieldOid = CSSMOID_APPLE_TP_REVOCATION_CRL;
322
323		crlOpts.Version = CSSM_APPLE_TP_CRL_OPTS_VERSION;
324		crlOpts.CrlFlags = 0;
325		crlOpts.crlStore = NULL;
326		policyPtr->FieldValue.Data = (uint8 *)&crlOpts;
327		policyPtr->FieldValue.Length = sizeof(crlOpts);
328		if(vfyArgs->requireCrlForAll) {
329			crlOpts.CrlFlags |= CSSM_TP_ACTION_REQUIRE_CRL_PER_CERT;
330		}
331		if(vfyArgs->crlNetFetchEnable) {
332			crlOpts.CrlFlags |= CSSM_TP_ACTION_FETCH_CRL_FROM_NET;
333		}
334		if(vfyArgs->requireCrlIfPresent) {
335			crlOpts.CrlFlags |= CSSM_TP_ACTION_REQUIRE_CRL_IF_PRESENT;
336		}
337		crlOpts.crlStore = vfyArgs->crlDlDb;
338		policyPtr++;
339		numPolicies++;
340	}
341
342	CSSM_APPLE_TP_OCSP_OPTIONS ocspOpts;
343	CSSM_DATA respUriData;
344	CSSM_DATA respCertData = {vfyArgs->responderCertLen,
345			(uint8 *)vfyArgs->responderCert};
346	if((vfyArgs->revokePolicy == CRP_OCSP) || (vfyArgs->revokePolicy == CRP_CRL_OCSP)) {
347		memset(&ocspOpts, 0, sizeof(ocspOpts));
348		policyPtr->FieldOid = CSSMOID_APPLE_TP_REVOCATION_OCSP;
349
350		crlOpts.Version = CSSM_APPLE_TP_OCSP_OPTS_VERSION;
351		policyPtr->FieldValue.Data = (uint8 *)&ocspOpts;
352		policyPtr->FieldValue.Length = sizeof(ocspOpts);
353		if(vfyArgs->requireOcspForAll) {
354			ocspOpts.Flags |= CSSM_TP_ACTION_OCSP_REQUIRE_PER_CERT;
355		}
356		if(vfyArgs->requireOcspIfPresent) {
357			ocspOpts.Flags |= CSSM_TP_ACTION_OCSP_REQUIRE_IF_RESP_PRESENT;
358		}
359		if(vfyArgs->disableCache) {
360			ocspOpts.Flags |= (CSSM_TP_ACTION_OCSP_CACHE_READ_DISABLE |
361						       CSSM_TP_ACTION_OCSP_CACHE_WRITE_DISABLE);
362		}
363		if(vfyArgs->disableOcspNet) {
364			ocspOpts.Flags |= CSSM_TP_ACTION_OCSP_DISABLE_NET;
365		}
366		if(vfyArgs->generateOcspNonce) {
367			ocspOpts.Flags |= CSSM_TP_OCSP_GEN_NONCE;
368		}
369		if(vfyArgs->requireOcspRespNonce) {
370			ocspOpts.Flags |= CSSM_TP_OCSP_REQUIRE_RESP_NONCE;
371		}
372		if(vfyArgs->responderURI != NULL) {
373			respUriData.Data = (uint8 *)vfyArgs->responderURI;
374			respUriData.Length = strlen(vfyArgs->responderURI);
375			ocspOpts.LocalResponder = &respUriData;
376		}
377		if(vfyArgs->responderCert != NULL) {
378			ocspOpts.LocalResponderCert = &respCertData;
379		}
380		/* other OCSP options here */
381		policyPtr++;
382		numPolicies++;
383	}
384
385	authCtx.Policy.NumberOfPolicyIds = numPolicies;
386
387	authCtx.Policy.PolicyIds = policyIds;
388	authCtx.Policy.PolicyControl = NULL;
389
390	authCtx.VerifyTime = vfyArgs->vfyTime;			// may be NULL
391	authCtx.VerificationAbortOn = CSSM_TP_STOP_ON_POLICY;
392	authCtx.CallbackWithVerifiedCert = NULL;
393
394	/*
395	 * DLDBs - the caller's optional set, plus two more we open
396	 * if trust settings are enabled and we're told to use system
397	 * anchors. (System anchors are normally passed in via
398	 * authCtx.AnchorCerts; they're passed in as DLDBs when
399	 * using TrustSettings.)
400	 */
401	uint32 totalNumDbs = 0;
402	uint32 numCallerDbs = 0;
403	CSSM_BOOL weOpenedDbs = CSSM_FALSE;
404	if(vfyArgs->dlDbList != NULL) {
405		totalNumDbs = numCallerDbs = vfyArgs->dlDbList->NumHandles;
406	}
407	if(vfyArgs->useTrustSettings && vfyArgs->useSystemAnchors) {
408		/* we'll cook up two more DBs and possible append them */
409		totalNumDbs += 2;
410		weOpenedDbs = CSSM_TRUE;
411	}
412	CSSM_DL_DB_HANDLE dlDbHandles[totalNumDbs];
413	CSSM_DL_DB_LIST dlDbList;
414	CSSM_DL_HANDLE dlHand = 0;
415	for(unsigned dex=0; dex<numCallerDbs; dex++) {
416		dlDbHandles[dex] = vfyArgs->dlDbList->DLDBHandle[dex];
417	}
418	if(weOpenedDbs) {
419		/* get a DL handle, somehow */
420		if(numCallerDbs == 0) {
421			/* new DL handle */
422			dlHand = cuDlStartup();
423			dlDbHandles[0].DLHandle = dlHand;
424			dlDbHandles[1].DLHandle = dlHand;
425		}
426		else {
427			/* use the same one caller passed in */
428			dlDbHandles[numCallerDbs].DLHandle     = dlDbHandles[0].DLHandle;
429			dlDbHandles[numCallerDbs + 1].DLHandle = dlDbHandles[0].DLHandle;
430		}
431		/* now open two DBs */
432		dlDbHandles[numCallerDbs].DBHandle =
433			cuDbStartupByName(dlDbHandles[numCallerDbs].DLHandle,
434				(char *)ADMIN_CERT_STORE_PATH, CSSM_FALSE, CSSM_TRUE);
435		dlDbHandles[numCallerDbs + 1].DBHandle =
436			cuDbStartupByName(dlDbHandles[numCallerDbs].DLHandle,
437				(char *)SYSTEM_ROOT_STORE_PATH, CSSM_FALSE, CSSM_TRUE);
438	}
439	dlDbList.DLDBHandle = dlDbHandles;
440	dlDbList.NumHandles = totalNumDbs;
441	authCtx.DBList = &dlDbList;
442
443	CFArrayRef cfAnchors = NULL;
444	CSSM_DATA *cssmAnchors = NULL;
445	unsigned numAnchors = 0;
446
447	if(vfyArgs->useSystemAnchors) {
448		if(!vfyArgs->useTrustSettings) {
449			/* standard system anchors - ingore error, I'm sure the
450			 * current test will eventually fail */
451			getSystemAnchors(&cfAnchors, &cssmAnchors, &numAnchors);
452			authCtx.NumberOfAnchorCerts = numAnchors;
453			authCtx.AnchorCerts = cssmAnchors;
454		}
455	}
456	else {
457		/* anchors are our caller's roots */
458		if(vfyArgs->roots) {
459			authCtx.NumberOfAnchorCerts = vfyArgs->roots->numBlobs();
460			authCtx.AnchorCerts = vfyArgs->roots->blobList();
461		}
462	}
463	authCtx.CallerCredentials = NULL;
464
465	if(vfyArgs->crls) {
466		/* cook up CRL group */
467		CSSM_CRLGROUP_PTR cssmCrls = &vfyCtx.Crls;
468		cssmCrls->CrlType = CSSM_CRL_TYPE_X_509v1;
469		cssmCrls->CrlEncoding = CSSM_CRL_ENCODING_DER;
470		cssmCrls->NumberOfCrls = vfyArgs->crls->numBlobs();
471		cssmCrls->GroupCrlList.CrlList = vfyArgs->crls->blobList();
472		cssmCrls->CrlGroupType = CSSM_CRLGROUP_DATA;
473	}
474
475	/* CSSM_APPLE_TP_ACTION_DATA */
476	CSSM_APPLE_TP_ACTION_DATA tpAction;
477	tpAction.Version = CSSM_APPLE_TP_ACTION_VERSION;
478	tpAction.ActionFlags = 0;
479	if(vfyArgs->leafCertIsCA) {
480		tpAction.ActionFlags |= CSSM_TP_ACTION_LEAF_IS_CA;
481	}
482	if(vfyArgs->certNetFetchEnable) {
483		tpAction.ActionFlags |= CSSM_TP_ACTION_FETCH_CERT_FROM_NET;
484	}
485	if(vfyArgs->allowExpiredRoot) {
486		tpAction.ActionFlags |= CSSM_TP_ACTION_ALLOW_EXPIRED_ROOT;
487	}
488	if(!vfyArgs->allowUnverified) {
489		tpAction.ActionFlags |= CSSM_TP_ACTION_REQUIRE_REV_PER_CERT;
490	}
491	if(vfyArgs->useTrustSettings) {
492		tpAction.ActionFlags |= CSSM_TP_ACTION_TRUST_SETTINGS;
493	}
494	if(vfyArgs->implicitAnchors) {
495		tpAction.ActionFlags |= CSSM_TP_ACTION_IMPLICIT_ANCHORS;
496	}
497
498	/* CSSM_TP_VERIFY_CONTEXT */
499	vfyCtx.ActionData.Data   = (uint8 *)&tpAction;
500	vfyCtx.ActionData.Length = sizeof(tpAction);
501
502	vfyCtx.Action = CSSM_TP_ACTION_DEFAULT;
503	vfyCtx.Cred = &authCtx;
504
505	/* cook up cert group */
506	CSSM_CERTGROUP cssmCerts;
507	cssmCerts.CertType = CSSM_CERT_X_509v3;
508	cssmCerts.CertEncoding = CSSM_CERT_ENCODING_DER;
509	cssmCerts.NumCerts = vfyArgs->certs->numBlobs();
510	cssmCerts.GroupList.CertList = vfyArgs->certs->blobList();
511	cssmCerts.CertGroupType = CSSM_CERTGROUP_DATA;
512
513	int ourRtn = 0;
514	CSSM_RETURN crtn = CSSM_TP_CertGroupVerify(vfyArgs->tpHand,
515		vfyArgs->clHand,
516		vfyArgs->cspHand,
517		&cssmCerts,
518		&vfyCtx,
519		&vfyResult);
520	if(vfyArgs->expectedErrStr != NULL) {
521		const char *actRtn;
522		if(crtn == CSSM_OK) {
523			/* cssmErrorString munges this to "[ok]" */
524			actRtn = "CSSM_OK";
525		}
526		else {
527			actRtn = cssmErrToStr(crtn);
528		}
529		char *found = strstr(actRtn, vfyArgs->expectedErrStr);
530		if(found) {
531			if(!vfyArgs->quiet) {
532				printf("...%s received as expected\n", vfyArgs->expectedErrStr);
533			}
534		}
535		else {
536			printf("***CSSM_TP_CertGroupVerify error\n");
537			printf("   expected rtn : %s\n", vfyArgs->expectedErrStr);
538			printf("     actual rtn : %s\n", actRtn);
539			ourRtn = 1;
540		}
541	}
542	else {
543		if(crtn) {
544			if(!vfyArgs->quiet) {
545				printError("CSSM_TP_CertGroupVerify", crtn);
546			}
547			ourRtn = 1;
548		}
549		else if(!vfyArgs->quiet) {
550			printf("...verify successful\n");
551		}
552	}
553	if(vfyArgs->certErrors) {
554		if(vfyCertErrors(&vfyResult, vfyArgs->numCertErrors, vfyArgs->certErrors,
555				vfyArgs->quiet)) {
556			ourRtn = 1;
557		}
558	}
559	if(vfyArgs->certStatus) {
560		if(vfyCertStatus(&vfyResult, vfyArgs->numCertStatus, vfyArgs->certStatus,
561				vfyArgs->quiet)) {
562			ourRtn = 1;
563		}
564	}
565	if(vfyArgs->verbose) {
566		dumpVfyResult(&vfyResult);
567	}
568	freeVfyResult(&vfyResult);
569	if(weOpenedDbs) {
570		/* close the DBs and maybe the DL we opened */
571		CSSM_DL_DbClose(dlDbHandles[numCallerDbs]);
572		CSSM_DL_DbClose(dlDbHandles[numCallerDbs + 1]);
573		if(dlHand != 0) {
574			cuDlDetachUnload(dlHand);
575		}
576	}
577	if(cfAnchors) {
578		CFRelease(cfAnchors);
579	}
580	if(cssmAnchors) {
581		free(cssmAnchors);
582	}
583	return ourRtn;
584}
585
586unsigned hexDigit(char digit)
587{
588	if((digit >= '0') && (digit <= '9')) {
589		return digit - '0';
590	}
591	if((digit >= 'a') && (digit <= 'f')) {
592		return 10 + digit - 'a';
593	}
594	if((digit >= 'A') && (digit <= 'F')) {
595		return 10 + digit - 'A';
596	}
597	printf("***BAD HEX DIGIT (%c)\n", digit);
598	return 0;
599}
600
601/* convert ASCII string in hex to unsigned */
602unsigned hexToBin(const char *hex)
603{
604	unsigned rtn = 0;
605	const char *cp = hex;
606	if((cp[0] == '0') && (cp[1] == 'x')) {
607		cp += 2;
608	}
609	if(strlen(cp) > 8) {
610		printf("***BAD HEX STRING (%s)\n", cp);
611		return 0;
612	}
613	while(*cp) {
614		rtn <<= 4;
615		rtn += hexDigit(*cp);
616		cp++;
617	}
618	return rtn;
619}
620
621/*
622 * A slightly simplified version of certVerify:
623 *		-- no CRLs (includes allowUnverified = CSSM_FALSE)
624 *		-- revokePOlicy = None
625 *		-- no DlDbs
626 *		-- no net fetch
627 *		-- time = now.
628 */
629int certVerifySimple(
630	CSSM_TP_HANDLE			tpHand,
631	CSSM_CL_HANDLE 			clHand,
632	CSSM_CSP_HANDLE 		cspHand,
633	BlobList				&certs,
634	BlobList				&roots,
635	CSSM_BOOL				useSystemAnchors,
636	CSSM_BOOL				leafCertIsCA,
637	CSSM_BOOL				allowExpiredRoot,
638	CertVerifyPolicy		vfyPolicy,
639	const char				*sslHost,		// optional, SSL policy
640	CSSM_BOOL				sslClient,		// normally server side
641	const char				*senderEmail,	// optional, SMIME
642	CE_KeyUsage				intendedKeyUse,	// optional, SMIME only
643	const char				*expectedErrStr,// e.g.,
644											// "CSSMERR_APPLETP_CRL_NOT_TRUSTED"
645
646	/*
647	 * expected per-cert errors
648	 * format is certNum:errorString
649	 * e.g., "1:CSSMERR_APPLETP_CRL_NOT_TRUSTED"
650	 */
651	unsigned 				numCertErrors,
652	const char 				**certErrors,	// per-cert status
653
654	/*
655	 * Expected per-cert status (CSSM_TP_APPLE_EVIDENCE_INFO.StatusBits)
656	 * format is certNum:status_in_hex
657	 * e.g., "1:0x18", leading 0x optional
658	 */
659	unsigned				numCertStatus,
660	const char				**certStatus,
661	CSSM_BOOL				useTrustSettings,
662	CSSM_BOOL				quiet,
663	CSSM_BOOL				verbose)
664{
665	CertVerifyArgs vfyArgs;
666	memset(&vfyArgs, 0, sizeof(vfyArgs));
667	vfyArgs.version = CERT_VFY_ARGS_VERS;
668	vfyArgs.tpHand = tpHand;
669	vfyArgs.clHand = clHand;
670	vfyArgs.cspHand = cspHand;
671	vfyArgs.certs = &certs;
672	vfyArgs.roots = &roots;
673	vfyArgs.useSystemAnchors = useSystemAnchors;
674	vfyArgs.useTrustSettings = useTrustSettings;
675	vfyArgs.leafCertIsCA = leafCertIsCA;
676	vfyArgs.allowExpiredRoot = allowExpiredRoot;
677	vfyArgs.vfyPolicy = vfyPolicy;
678	vfyArgs.sslHost = sslHost;
679	vfyArgs.sslClient = sslClient;
680	vfyArgs.senderEmail = senderEmail;
681	vfyArgs.intendedKeyUse = intendedKeyUse;
682	vfyArgs.allowUnverified = CSSM_TRUE;
683	vfyArgs.expectedErrStr = expectedErrStr;
684	vfyArgs.numCertErrors = numCertErrors;
685	vfyArgs.certErrors = certErrors;
686	vfyArgs.numCertStatus = numCertStatus;
687	vfyArgs.certStatus = certStatus;
688	vfyArgs.quiet = quiet;
689	vfyArgs.verbose = verbose;
690	return certVerify(&vfyArgs);
691}
692
693