1/*
2 * Copyright (c) 2001-2003,2011-2012,2014 Apple Inc. All Rights Reserved.
3 *
4 * The contents of this file constitute Original Code as defined in and are
5 * subject to the Apple Public Source License Version 1.2 (the 'License').
6 * You may not use this file except in compliance with the License. Please
7 * obtain a copy of the License at http://www.apple.com/publicsource and
8 * read it before using this file.
9 *
10 * This Original Code and all software distributed under the License are
11 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
12 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
13 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
14 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
15 * Please see the License for the specific language governing rights and
16 * limitations under the License.
17 */
18
19/*
20	File:		 cuCdsaUtils.cpp
21
22	Description: common CDSA access utilities
23
24	Author:		 dmitch
25*/
26
27#include "cuCdsaUtils.h"
28#include <stdlib.h>
29#include <stdio.h>
30#include <Security/SecCertificate.h>
31#include <Security/cssmapple.h>				/* for cssmPerror() */
32#include <Security/oidsalg.h>
33#include <Security/TrustSettingsSchema.h>
34#include <strings.h>
35
36static CSSM_VERSION vers = {2, 0};
37static const CSSM_GUID testGuid = { 0xFADE, 0, 0, { 1,2,3,4,5,6,7,0 }};
38
39/*
40 * Standard app-level memory functions required by CDSA.
41 */
42void * cuAppMalloc (CSSM_SIZE size, void *allocRef) {
43	return( malloc(size) );
44}
45
46void cuAppFree (void *mem_ptr, void *allocRef) {
47	free(mem_ptr);
48 	return;
49}
50
51void * cuAppRealloc (void *ptr, CSSM_SIZE size, void *allocRef) {
52	return( realloc( ptr, size ) );
53}
54
55void * cuAppCalloc (uint32 num, CSSM_SIZE size, void *allocRef) {
56	return( calloc( num, size ) );
57}
58
59static CSSM_API_MEMORY_FUNCS memFuncs = {
60	cuAppMalloc,
61	cuAppFree,
62	cuAppRealloc,
63 	cuAppCalloc,
64 	NULL
65 };
66
67CSSM_BOOL cuCompareCssmData(const CSSM_DATA *d1,
68	const CSSM_DATA *d2)
69{
70	if(d1->Length != d2->Length) {
71		return CSSM_FALSE;
72	}
73	if(memcmp(d1->Data, d2->Data, d1->Length)) {
74		return CSSM_FALSE;
75	}
76	return CSSM_TRUE;
77}
78
79/*
80 * Init CSSM; returns CSSM_FALSE on error. Reusable.
81 */
82static CSSM_BOOL cssmInitd = CSSM_FALSE;
83
84CSSM_BOOL cuCssmStartup()
85{
86	CSSM_RETURN  crtn;
87    CSSM_PVC_MODE pvcPolicy = CSSM_PVC_NONE;
88
89	if(cssmInitd) {
90		return CSSM_TRUE;
91	}
92	crtn = CSSM_Init (&vers,
93		CSSM_PRIVILEGE_SCOPE_NONE,
94		&testGuid,
95		CSSM_KEY_HIERARCHY_NONE,
96		&pvcPolicy,
97		NULL /* reserved */);
98	if(crtn != CSSM_OK)
99	{
100		cuPrintError("CSSM_Init", crtn);
101		return CSSM_FALSE;
102	}
103	else {
104		cssmInitd = CSSM_TRUE;
105		return CSSM_TRUE;
106	}
107}
108
109/*
110 * Attach to CSP. Returns zero on error.
111 */
112CSSM_CSP_HANDLE cuCspStartup(
113	CSSM_BOOL bareCsp)		// true ==> CSP, false ==> CSP/DL
114{
115	CSSM_CSP_HANDLE cspHand;
116	CSSM_RETURN		crtn;
117	const CSSM_GUID *guid;
118
119	/* common CSSM init */
120	if(cuCssmStartup() == CSSM_FALSE) {
121		return 0;
122	}
123	if(bareCsp) {
124		guid = &gGuidAppleCSP;
125	}
126	else {
127		guid = &gGuidAppleCSPDL;
128	}
129	crtn = CSSM_ModuleLoad(guid,
130		CSSM_KEY_HIERARCHY_NONE,
131		NULL,			// eventHandler
132		NULL);			// AppNotifyCallbackCtx
133	if(crtn) {
134		cuPrintError("CSSM_ModuleLoad()", crtn);
135		return 0;
136	}
137	crtn = CSSM_ModuleAttach (guid,
138		&vers,
139		&memFuncs,			// memFuncs
140		0,					// SubserviceID
141		CSSM_SERVICE_CSP,
142		0,					// AttachFlags
143		CSSM_KEY_HIERARCHY_NONE,
144		NULL,				// FunctionTable
145		0,					// NumFuncTable
146		NULL,				// reserved
147		&cspHand);
148	if(crtn) {
149		cuPrintError("CSSM_ModuleAttach()", crtn);
150		return 0;
151	}
152	return cspHand;
153}
154
155/* Attach to DL side of CSPDL */
156CSSM_DL_HANDLE cuDlStartup()
157{
158	CSSM_DL_HANDLE 	dlHand = 0;
159	CSSM_RETURN		crtn;
160
161	if(cuCssmStartup() == CSSM_FALSE) {
162		return 0;
163	}
164	crtn = CSSM_ModuleLoad(&gGuidAppleCSPDL,
165		CSSM_KEY_HIERARCHY_NONE,
166		NULL,			// eventHandler
167		NULL);			// AppNotifyCallbackCtx
168	if(crtn) {
169		cuPrintError("CSSM_ModuleLoad(Apple CSPDL)", crtn);
170		return 0;
171	}
172	crtn = CSSM_ModuleAttach (&gGuidAppleCSPDL,
173		&vers,
174		&memFuncs,			// memFuncs
175		0,					// SubserviceID
176		CSSM_SERVICE_DL,
177		0,					// AttachFlags
178		CSSM_KEY_HIERARCHY_NONE,
179		NULL,				// FunctionTable
180		0,					// NumFuncTable
181		NULL,				// reserved
182		&dlHand);
183	if(crtn) {
184		cuPrintError("CSSM_ModuleAttach(Apple CSPDL)", crtn);
185		return 0;
186	}
187	return dlHand;
188}
189
190CSSM_CL_HANDLE cuClStartup()
191{
192	CSSM_CL_HANDLE clHand;
193	CSSM_RETURN crtn;
194
195	if(cuCssmStartup() == CSSM_FALSE) {
196		return 0;
197	}
198	crtn = CSSM_ModuleLoad(&gGuidAppleX509CL,
199		CSSM_KEY_HIERARCHY_NONE,
200		NULL,			// eventHandler
201		NULL);			// AppNotifyCallbackCtx
202	if(crtn) {
203		cuPrintError("CSSM_ModuleLoad(AppleCL)", crtn);
204		return 0;
205	}
206	crtn = CSSM_ModuleAttach (&gGuidAppleX509CL,
207		&vers,
208		&memFuncs,				// memFuncs
209		0,						// SubserviceID
210		CSSM_SERVICE_CL,		// SubserviceFlags - Where is this used?
211		0,						// AttachFlags
212		CSSM_KEY_HIERARCHY_NONE,
213		NULL,					// FunctionTable
214		0,						// NumFuncTable
215		NULL,					// reserved
216		&clHand);
217	if(crtn) {
218		cuPrintError("CSSM_ModuleAttach(AppleCL)", crtn);
219		return 0;
220	}
221	else {
222		return clHand;
223	}
224}
225
226CSSM_TP_HANDLE cuTpStartup()
227{
228	CSSM_TP_HANDLE tpHand;
229	CSSM_RETURN crtn;
230
231	if(cuCssmStartup() == CSSM_FALSE) {
232		return 0;
233	}
234	crtn = CSSM_ModuleLoad(&gGuidAppleX509TP,
235		CSSM_KEY_HIERARCHY_NONE,
236		NULL,			// eventHandler
237		NULL);			// AppNotifyCallbackCtx
238	if(crtn) {
239		cuPrintError("CSSM_ModuleLoad(AppleTP)", crtn);
240		return 0;
241	}
242	crtn = CSSM_ModuleAttach (&gGuidAppleX509TP,
243		&vers,
244		&memFuncs,				// memFuncs
245		0,						// SubserviceID
246		CSSM_SERVICE_TP,		// SubserviceFlags
247		0,						// AttachFlags
248		CSSM_KEY_HIERARCHY_NONE,
249		NULL,					// FunctionTable
250		0,						// NumFuncTable
251		NULL,					// reserved
252		&tpHand);
253	if(crtn) {
254		cuPrintError("CSSM_ModuleAttach(AppleTP)", crtn);
255		return 0;
256	}
257	else {
258		return tpHand;
259	}
260}
261
262/* detach and unload */
263CSSM_RETURN cuCspDetachUnload(
264	CSSM_CSP_HANDLE cspHand,
265	CSSM_BOOL bareCsp)					// true ==> CSP, false ==> CSP/DL
266{
267	CSSM_RETURN crtn = CSSM_ModuleDetach(cspHand);
268	if(crtn) {
269		return crtn;
270	}
271	const CSSM_GUID *guid;
272	if(bareCsp) {
273		guid = &gGuidAppleCSP;
274	}
275	else {
276		guid = &gGuidAppleCSPDL;
277	}
278	return CSSM_ModuleUnload(guid, NULL, NULL);
279}
280
281CSSM_RETURN cuClDetachUnload(
282	CSSM_CL_HANDLE  clHand)
283{
284	CSSM_RETURN crtn = CSSM_ModuleDetach(clHand);
285	if(crtn) {
286		return crtn;
287	}
288	return CSSM_ModuleUnload(&gGuidAppleX509CL, NULL, NULL);
289
290}
291
292CSSM_RETURN cuDlDetachUnload(
293	CSSM_DL_HANDLE  dlHand)
294{
295	CSSM_RETURN crtn = CSSM_ModuleDetach(dlHand);
296	if(crtn) {
297		return crtn;
298	}
299	return CSSM_ModuleUnload(&gGuidAppleCSPDL, NULL, NULL);
300
301}
302CSSM_RETURN cuTpDetachUnload(
303	CSSM_TP_HANDLE  tpHand)
304{
305	CSSM_RETURN crtn = CSSM_ModuleDetach(tpHand);
306	if(crtn) {
307		return crtn;
308	}
309	return CSSM_ModuleUnload(&gGuidAppleX509TP, NULL, NULL);
310
311}
312
313/*
314 * open a DB, ensure it's empty.
315 */
316CSSM_DB_HANDLE cuDbStartup(
317	CSSM_DL_HANDLE		dlHand,			// from dlStartup()
318	const char 			*dbName)
319{
320	CSSM_DB_HANDLE				dbHand = 0;
321	CSSM_RETURN					crtn;
322	CSSM_DBINFO					dbInfo;
323
324	/* first delete possible existing DB, ignore error */
325	crtn = CSSM_DL_DbDelete(dlHand, dbName, NULL, NULL);
326	switch(crtn) {
327		/* only allowed error is "no such file" */
328		case CSSM_OK:
329		case CSSMERR_DL_DATASTORE_DOESNOT_EXIST:
330			break;
331		default:
332			cuPrintError("CSSM_DL_DbDelete", crtn);
333			return 0;
334	}
335
336	memset(&dbInfo, 0, sizeof(CSSM_DBINFO));
337
338	/* now create it */
339	crtn = CSSM_DL_DbCreate(dlHand,
340		dbName,
341		NULL,						// DbLocation
342		&dbInfo,
343		// &Security::KeychainCore::Schema::DBInfo,
344		CSSM_DB_ACCESS_PRIVILEGED,
345		NULL,						// CredAndAclEntry
346		NULL,						// OpenParameters
347		&dbHand);
348	if(crtn) {
349		cuPrintError("CSSM_DL_DbCreate", crtn);
350	}
351	return dbHand;
352}
353
354/*
355 * Attach to existing DB or create an empty new one.
356 */
357CSSM_DB_HANDLE cuDbStartupByName(CSSM_DL_HANDLE dlHand,
358	char 		*dbName,
359	CSSM_BOOL 	doCreate,
360	CSSM_BOOL	quiet)
361{
362	CSSM_RETURN 	crtn;
363	CSSM_DB_HANDLE	dbHand;
364
365	/* try open existing DB in either case */
366
367	crtn = CSSM_DL_DbOpen(dlHand,
368		dbName,
369		NULL,			// DbLocation
370		CSSM_DB_ACCESS_READ | CSSM_DB_ACCESS_WRITE,
371		NULL, 			// CSSM_ACCESS_CREDENTIALS *AccessCred
372		NULL,			// void *OpenParameters
373		&dbHand);
374	if(crtn == CSSM_OK) {
375		return dbHand;
376	}
377	if(!doCreate) {
378		if(!quiet) {
379			printf("***no such data base (%s)\n", dbName);
380			cuPrintError("CSSM_DL_DbOpen", crtn);
381		}
382		return 0;
383	}
384	/* have to create one */
385	return cuDbStartup(dlHand, dbName);
386}
387
388/*
389 * Given a context specified via a CSSM_CC_HANDLE, add a new
390 * CSSM_CONTEXT_ATTRIBUTE to the context as specified by AttributeType,
391 * AttributeLength, and an untyped pointer.
392 */
393static
394CSSM_RETURN cuAddContextAttribute(CSSM_CC_HANDLE CCHandle,
395	uint32 AttributeType,
396	uint32 AttributeLength,
397	const void *AttributePtr)
398{
399	CSSM_CONTEXT_ATTRIBUTE		newAttr;
400	CSSM_RETURN					crtn;
401
402	newAttr.AttributeType     = AttributeType;
403	newAttr.AttributeLength   = AttributeLength;
404	newAttr.Attribute.Data    = (CSSM_DATA_PTR)AttributePtr;
405	crtn = CSSM_UpdateContextAttributes(CCHandle, 1, &newAttr);
406	if(crtn) {
407		cuPrintError("CSSM_UpdateContextAttributes", crtn);
408	}
409	return crtn;
410}
411
412
413/*
414 * Derive symmetric key.
415 * Note in the X CSP, we never return an IV.
416 */
417CSSM_RETURN cuCspDeriveKey(CSSM_CSP_HANDLE cspHand,
418		uint32				keyAlg,			// CSSM_ALGID_RC5, etc.
419		const char 			*keyLabel,
420		unsigned 			keyLabelLen,
421		uint32 				keyUsage,		// CSSM_KEYUSE_ENCRYPT, etc.
422		uint32 				keySizeInBits,
423		CSSM_DATA_PTR		password,		// in PKCS-5 lingo
424		CSSM_DATA_PTR		salt,			// ditto
425		uint32				iterationCnt,	// ditto
426		CSSM_KEY_PTR		key)
427{
428	CSSM_RETURN					crtn;
429	CSSM_CC_HANDLE 				ccHand;
430	uint32						keyAttr;
431	CSSM_DATA					dummyLabel;
432	CSSM_PKCS5_PBKDF2_PARAMS 	pbeParams;
433	CSSM_DATA					pbeData;
434	CSSM_ACCESS_CREDENTIALS		creds;
435
436	memset(key, 0, sizeof(CSSM_KEY));
437	memset(&creds, 0, sizeof(CSSM_ACCESS_CREDENTIALS));
438	crtn = CSSM_CSP_CreateDeriveKeyContext(cspHand,
439		CSSM_ALGID_PKCS5_PBKDF2,
440		keyAlg,
441		keySizeInBits,
442		&creds,
443		NULL,			// BaseKey
444		iterationCnt,
445		salt,
446		NULL,			// seed
447		&ccHand);
448	if(crtn) {
449		cuPrintError("CSSM_CSP_CreateDeriveKeyContext", crtn);
450		return crtn;
451	}
452	keyAttr = CSSM_KEYATTR_EXTRACTABLE | CSSM_KEYATTR_RETURN_REF |
453			  CSSM_KEYATTR_SENSITIVE;
454	dummyLabel.Length = keyLabelLen;
455	dummyLabel.Data = (uint8 *)keyLabel;
456
457	/* passing in password is pretty strange....*/
458	pbeParams.Passphrase = *password;
459	pbeParams.PseudoRandomFunction = CSSM_PKCS5_PBKDF2_PRF_HMAC_SHA1;
460	pbeData.Data = (uint8 *)&pbeParams;
461	pbeData.Length = sizeof(pbeParams);
462	crtn = CSSM_DeriveKey(ccHand,
463		&pbeData,
464		keyUsage,
465		keyAttr,
466		&dummyLabel,
467		NULL,			// cred and acl
468		key);
469	if(crtn) {
470		cuPrintError("CSSM_DeriveKey", crtn);
471		return crtn;
472	}
473	crtn = CSSM_DeleteContext(ccHand);
474	if(crtn) {
475		cuPrintError("CSSM_DeleteContext", crtn);
476	}
477	return crtn;
478}
479
480/*
481 * Generate key pair of arbitrary algorithm.
482 */
483
484/* CSP DL currently does not perform DSA generate params; let CSP do it implicitly */
485#define DO_DSA_GEN_PARAMS		0
486
487CSSM_RETURN cuCspGenKeyPair(CSSM_CSP_HANDLE cspHand,
488	CSSM_DL_DB_HANDLE *dlDbHand,	// optional
489	uint32 algorithm,
490	const char *keyLabel,
491	unsigned keyLabelLen,
492	uint32 keySize,					// in bits
493	CSSM_KEY_PTR pubKey,			// mallocd by caller
494	CSSM_KEYUSE pubKeyUsage,		// CSSM_KEYUSE_ENCRYPT, etc.
495	CSSM_KEYATTR_FLAGS pubAttrs,	// CSSM_KEYATTR_EXTRACTABLE, etc.
496	CSSM_KEY_PTR privKey,			// mallocd by caller
497	CSSM_KEYUSE privKeyUsage,		// CSSM_KEYUSE_DECRYPT, etc.
498	CSSM_KEYATTR_FLAGS privAttrs)	// CSSM_KEYATTR_EXTRACTABLE, etc.
499{
500	CSSM_RETURN				crtn;
501	CSSM_RETURN				ocrtn;
502	CSSM_CC_HANDLE 			ccHand;
503	CSSM_DATA				keyLabelData;
504
505	keyLabelData.Data        = (uint8 *)keyLabel,
506	keyLabelData.Length      = keyLabelLen;
507	memset(pubKey, 0, sizeof(CSSM_KEY));
508	memset(privKey, 0, sizeof(CSSM_KEY));
509
510	crtn = CSSM_CSP_CreateKeyGenContext(cspHand,
511		algorithm,
512		keySize,
513		NULL,					// Seed
514		NULL,					// Salt
515		NULL,					// StartDate
516		NULL,					// EndDate
517		NULL,					// Params
518		&ccHand);
519	if(crtn) {
520		cuPrintError("CSSM_CSP_CreateKeyGenContext", crtn);
521		return crtn;
522	}
523
524	/* post-context-create algorithm-specific stuff */
525	switch(algorithm) {
526		#if DO_DSA_GEN_PARAMS
527		case CSSM_ALGID_DSA:
528			/*
529			 * extra step - generate params - this just adds some
530			 * info to the context
531			 */
532			{
533				CSSM_DATA dummy = {0, NULL};
534				crtn = CSSM_GenerateAlgorithmParams(ccHand,
535					keySize, &dummy);
536				if(crtn) {
537					cuPrintError("CSSM_GenerateAlgorithmParams", crtn);
538					CSSM_DeleteContext(ccHand);
539					return crtn;
540				}
541				cuAppFree(dummy.Data, NULL);
542			}
543			break;
544		#endif	/* DO_DSA_GEN_PARAMS */
545		default:
546			break;
547	}
548
549	/* optionally specify DL/DB storage location */
550	if(dlDbHand) {
551		crtn = cuAddContextAttribute(ccHand,
552			CSSM_ATTRIBUTE_DL_DB_HANDLE,
553			sizeof(CSSM_ATTRIBUTE_DL_DB_HANDLE),
554			dlDbHand);
555		if(crtn) {
556			CSSM_DeleteContext(ccHand);
557			return crtn;
558		}
559	}
560	ocrtn = CSSM_GenerateKeyPair(ccHand,
561		pubKeyUsage,
562		pubAttrs,
563		&keyLabelData,
564		pubKey,
565		privKeyUsage,
566		privAttrs,
567		&keyLabelData,			// same labels
568		NULL,					// CredAndAclEntry
569		privKey);
570	if(ocrtn) {
571		cuPrintError("CSSM_GenerateKeyPair", ocrtn);
572	}
573	crtn = CSSM_DeleteContext(ccHand);
574	if(crtn) {
575		cuPrintError("CSSM_DeleteContext", crtn);
576		if(ocrtn == CSSM_OK) {
577			/* error on CSSM_GenerateKeyPair takes precedence */
578			ocrtn = crtn;
579		}
580	}
581	return ocrtn;
582}
583
584
585/*
586 * Add a certificate to an open Keychain.
587 */
588CSSM_RETURN cuAddCertToKC(
589	SecKeychainRef		keychain,
590	const CSSM_DATA		*cert,
591	CSSM_CERT_TYPE		certType,
592	CSSM_CERT_ENCODING	certEncoding,
593	const char			*printName,		// C string
594	const CSSM_DATA		*keyLabel)		// ??
595{
596	SecCertificateRef certificate;
597
598	OSStatus rslt = SecCertificateCreateFromData(cert, certType, certEncoding, &certificate);
599	if (!rslt)
600	{
601		rslt = SecCertificateAddToKeychain(certificate, keychain);
602		CFRelease(certificate);
603	}
604
605	return rslt;
606}
607
608/*
609 * Convert a CSSM_DATA_PTR, referring to a DER-encoded int, to an
610 * unsigned.
611 */
612unsigned cuDER_ToInt(const CSSM_DATA *DER_Data)
613{
614	uint32		rtn = 0;
615	unsigned	i = 0;
616
617	while(i < DER_Data->Length) {
618		rtn |= DER_Data->Data[i];
619		if(++i == DER_Data->Length) {
620			break;
621		}
622		rtn <<= 8;
623	}
624	return rtn;
625}
626
627/*
628 * Log CSSM error.
629 */
630void cuPrintError(const char *op, CSSM_RETURN err)
631{
632	cssmPerror(op, err);
633}
634
635/*
636 * Verify a CRL against system anchors and intermediate certs.
637 */
638CSSM_RETURN cuCrlVerify(
639	CSSM_TP_HANDLE			tpHand,
640	CSSM_CL_HANDLE 			clHand,
641	CSSM_CSP_HANDLE 		cspHand,
642	const CSSM_DATA			*crlData,
643	CSSM_DL_DB_HANDLE_PTR	certKeychain,	// intermediate certs
644	const CSSM_DATA 		*anchors,		// optional - if NULL, use Trust Settings
645	uint32 					anchorCount)
646{
647	/* main job is building a CSSM_TP_VERIFY_CONTEXT and its components */
648	CSSM_TP_VERIFY_CONTEXT			vfyCtx;
649	CSSM_TP_CALLERAUTH_CONTEXT		authCtx;
650
651	memset(&vfyCtx, 0, sizeof(CSSM_TP_VERIFY_CONTEXT));
652	memset(&authCtx, 0, sizeof(CSSM_TP_CALLERAUTH_CONTEXT));
653
654	/* CSSM_TP_CALLERAUTH_CONTEXT components */
655	/*
656		typedef struct cssm_tp_callerauth_context {
657			CSSM_TP_POLICYINFO Policy;
658			CSSM_TIMESTRING VerifyTime;
659			CSSM_TP_STOP_ON VerificationAbortOn;
660			CSSM_TP_VERIFICATION_RESULTS_CALLBACK CallbackWithVerifiedCert;
661			uint32 NumberOfAnchorCerts;
662			CSSM_DATA_PTR AnchorCerts;
663			CSSM_DL_DB_LIST_PTR DBList;
664			CSSM_ACCESS_CREDENTIALS_PTR CallerCredentials;
665		} CSSM_TP_CALLERAUTH_CONTEXT, *CSSM_TP_CALLERAUTH_CONTEXT_PTR;
666	*/
667	CSSM_FIELD	policyId;
668	CSSM_APPLE_TP_CRL_OPTIONS crlOpts;
669	policyId.FieldOid = CSSMOID_APPLE_TP_REVOCATION_CRL;
670	policyId.FieldValue.Data = (uint8 *)&crlOpts;
671	policyId.FieldValue.Length = sizeof(crlOpts);
672	crlOpts.Version = CSSM_APPLE_TP_CRL_OPTS_VERSION;
673	/* perhaps this should be user-specifiable */
674	crlOpts.CrlFlags = CSSM_TP_ACTION_FETCH_CRL_FROM_NET;
675	crlOpts.crlStore = NULL;
676
677	authCtx.Policy.NumberOfPolicyIds = 1;
678	authCtx.Policy.PolicyIds = &policyId;
679	authCtx.Policy.PolicyControl = NULL;
680
681	authCtx.VerifyTime = NULL;
682	authCtx.VerificationAbortOn = CSSM_TP_STOP_ON_POLICY;
683	authCtx.CallbackWithVerifiedCert = NULL;
684
685	/* anchors */
686	authCtx.NumberOfAnchorCerts = anchorCount;
687	authCtx.AnchorCerts = const_cast<CSSM_DATA_PTR>(anchors);
688
689	/* DBList of intermediate certs, plus possible System.keychain and
690   	 * system roots */
691	CSSM_DL_DB_HANDLE handles[3];
692	unsigned numDbs = 0;
693	CSSM_DL_HANDLE dlHand = 0;
694	if(certKeychain != NULL) {
695		handles[0] = *certKeychain;
696		numDbs++;
697	}
698	if(anchors == NULL) {
699		/* Trust Settings requires two more DBs */
700		if(numDbs == 0) {
701			/* new DL handle */
702			dlHand = cuDlStartup();
703			handles[numDbs].DLHandle = dlHand;
704			handles[numDbs + 1].DLHandle = dlHand;
705		}
706		else {
707			/* use the same one passed in for certKeychain */
708			handles[numDbs].DLHandle = handles[0].DLHandle;
709			handles[numDbs + 1].DLHandle = handles[0].DLHandle;
710		}
711		handles[numDbs].DBHandle = cuDbStartupByName(handles[numDbs].DLHandle,
712			(char*) ADMIN_CERT_STORE_PATH, CSSM_FALSE, CSSM_TRUE);
713		numDbs++;
714
715		handles[numDbs].DBHandle = cuDbStartupByName(handles[numDbs].DLHandle,
716			(char*) SYSTEM_ROOT_STORE_PATH, CSSM_FALSE, CSSM_TRUE);
717		numDbs++;
718	}
719	CSSM_DL_DB_LIST dlDbList;
720	dlDbList.DLDBHandle = handles;
721	dlDbList.NumHandles = numDbs;
722
723	authCtx.DBList = &dlDbList;
724	authCtx.CallerCredentials = NULL;
725
726	/* CSSM_TP_VERIFY_CONTEXT */
727	vfyCtx.ActionData.Data = NULL;
728	vfyCtx.ActionData.Length = 0;
729	vfyCtx.Action = CSSM_TP_ACTION_DEFAULT;
730	vfyCtx.Cred = &authCtx;
731
732	/* CSSM_APPLE_TP_ACTION_DATA */
733	CSSM_APPLE_TP_ACTION_DATA tpAction;
734	if(anchors == NULL) {
735		/* enable Trust Settings */
736		tpAction.Version = CSSM_APPLE_TP_ACTION_VERSION;
737		tpAction.ActionFlags = CSSM_TP_ACTION_TRUST_SETTINGS;
738		vfyCtx.ActionData.Data   = (uint8 *)&tpAction;
739		vfyCtx.ActionData.Length = sizeof(tpAction);
740	}
741
742	/* cook up CSSM_ENCODED_CRL */
743	CSSM_ENCODED_CRL encCrl;
744	encCrl.CrlType = CSSM_CRL_TYPE_X_509v2;
745	encCrl.CrlEncoding = CSSM_CRL_ENCODING_DER;
746	encCrl.CrlBlob = *crlData;
747
748	/* CDSA API requires a SignerCertGroup; for us, all the certs are in
749	 * certKeyChain... */
750	CSSM_CERTGROUP certGroup;
751	certGroup.CertType = CSSM_CERT_X_509v1;
752	certGroup.CertEncoding = CSSM_CERT_ENCODING_DER;
753	certGroup.NumCerts = 0;
754	certGroup.GroupList.CertList = NULL;
755	certGroup.CertGroupType = CSSM_CERTGROUP_DATA;
756
757	CSSM_RETURN crtn = CSSM_TP_CrlVerify(tpHand,
758		clHand,
759		cspHand,
760		&encCrl,
761		&certGroup,
762		&vfyCtx,
763		NULL);			// RevokerVerifyResult
764	if(crtn) {
765		cuPrintError("CSSM_TP_CrlVerify", crtn);
766	}
767	if(anchors == NULL) {
768		/* close the DBs and maybe the DL we opened */
769		unsigned dexToClose = (certKeychain == NULL) ? 0 : 1;
770		CSSM_DL_DbClose(handles[dexToClose++]);
771		CSSM_DL_DbClose(handles[dexToClose]);
772		if(dlHand != 0) {
773			cuDlDetachUnload(dlHand);
774		}
775	}
776	return crtn;
777}
778
779