2 * Copyright (c) 2000-2001 Apple Computer, Inc. All Rights Reserved.
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 obtain
7 * a copy of the License at http://www.apple.com/publicsource and read it before
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 EXPRESS
12 * OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, INCLUDING WITHOUT
13 * LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
14 * PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. Please see the License for the
15 * specific language governing rights and limitations under the License.
20 * tpCertGroup.cpp - Cert group functions (construct, verify)
22 * Created 10/5/2000 by Doug Mitchell.
25 #include "AppleTPSession.h"
26 #include "certGroupUtils.h"
27 #include "TPCertInfo.h"
28 #include "TPCrlInfo.h"
29 #include "tpPolicies.h"
30 #include "tpdebugging.h"
31 #include "rootCerts.h"
32 #include "tpCrlVerify.h"
33 #include <Security/oidsalg.h>
34 #include <Security/cssmapple.h>
36 /*-----------------------------------------------------------------------------
40 * This function returns a pointer to a mallocd CSSM_CERTGROUP which
41 * refers to a mallocd list of raw ordered X.509 certs which verify back as
42 * far as the TP is able to go. The first cert of the returned list is the
43 * subject cert. The TP will attempt to search thru the DBs passed in
44 * DBList in order to complete the chain. The chain is completed when a
45 * self-signed (root) cert is found in the chain. The root cert may be
46 * present in the input CertGroupFrag, or it may have been obtained from
47 * one of the DBs passed in DBList. It is not an error if no root cert is
50 * The error conditions are:
51 * -- The first cert of CertGroupFrag is an invalid cert. NULL is returned,
52 * err = CSSM_TP_INVALID_CERTIFICATE.
53 * -- The root cert (if found) fails to verify. Valid certgroup is returned,
54 * err = CSSMERR_TP_VERIFICATION_FAILURE.
55 * -- Any cert in the (possibly partially) constructed chain has expired or
56 * isn't valid yet, err = CSSMERR_TP_CERT_EXPIRED or
57 * CSSMERR_TP_CERT_NOT_VALID_YET. A CertGroup is returned.
58 * -- CSSMERR_TP_CERT_EXPIRED and CSSMERR_TP_CERT_NOT_VALID_YET. If one of these
59 * conditions obtains for the first (leaf) cert, the function throws this
60 * error immediately and the outgoing cert group is empty. For subsequent certs,
61 * the temporal validity of a cert is only tested AFTER a cert successfully
62 * meets the cert chaining criteria (subject/issuer match and signature
63 * verify). A cert in a chain with this error is not added to the outgoing
65 * -- the usual errors like bad handle or memory failure.
68 * Two handles - to an open CL and CSP. The CSP must be capable of
69 * dealing with the signature algorithms used by the certs. The CL must be
72 * CertGroupFrag, an unordered array of raw X.509 certs in the form of a
73 * CSSM_CERTGROUP_PTR. The first cert of this list is the subject cert
74 * which is eventually to be verified. The other certs can be in any order
75 * and may not even have any relevance to the cert chain being constructed.
76 * They may also be invalid certs.
78 * DBList, a list of DB/DL handles which may contain certs necessary to
79 * complete the desired cert chain. (Not currently implemented.)
81 *---------------------------------------------------------------------------*/
84 void AppleTPSession::CertGroupConstruct(CSSM_CL_HANDLE clHand
,
85 CSSM_CSP_HANDLE cspHand
,
86 const CSSM_DL_DB_LIST
&DBList
,
87 const void *ConstructParams
,
88 const CSSM_CERTGROUP
&CertGroupFrag
,
89 CSSM_CERTGROUP_PTR
&CertGroup
)
91 TPCertGroup
outCertGroup(*this, TGO_Caller
);
92 TPCertGroup
inCertGroup(CertGroupFrag
,
97 true, // firstCertMustBeValid
100 /* set up for disposal of TPCertInfos created by CertGroupConstructPriv */
101 TPCertGroup
certsToBeFreed(*this, TGO_Group
);
103 CSSM_RETURN constructReturn
= CSSM_OK
;
104 CSSM_BOOL verifiedToRoot
; // not used
105 CSSM_BOOL verifiedToAnchor
; // not used
108 CertGroupConstructPriv(clHand
,
121 catch(const CssmError
&cerr
) {
122 constructReturn
= cerr
.cssmError();
123 /* abort if no certs found */
124 if(outCertGroup
.numCerts() == 0) {
125 CssmError::throwMe(constructReturn
);
128 CertGroup
= outCertGroup
.buildCssmCertGroup();
129 if(constructReturn
) {
130 CssmError::throwMe(constructReturn
);
136 * Private version of CertGroupConstruct, used by CertGroupConstruct and
137 * CertGroupVerify. Populates a TP-style TPCertGroup for further processing.
138 * This only throws CSSM-style exceptions in the following cases:
140 * -- input parameter errors
141 * -- the first (leaf) cert is bad (doesn't parse, expired, not valid yet).
142 * -- root found but it doesn't self-verify
144 * All other cert-related errors simply result in the bad cert being ignored.
145 * Other exceptions are gross system errors like malloc failure.
147 void AppleTPSession::CertGroupConstructPriv(CSSM_CL_HANDLE clHand
,
148 CSSM_CSP_HANDLE cspHand
,
149 TPCertGroup
&inCertGroup
,
150 const CSSM_DL_DB_LIST
*DBList
, // optional here
151 const char *cssmTimeStr
, // optional
153 /* trusted anchors, optional */
154 /* FIXME - maybe this should be a TPCertGroup */
155 uint32 numAnchorCerts
,
156 const CSSM_DATA
*anchorCerts
,
158 /* currently, only CSSM_TP_ACTION_FETCH_CERT_FROM_NET is
160 CSSM_APPLE_TP_ACTION_FLAGS actionFlags
,
162 * Certs to be freed by caller (i.e., TPCertInfo which we allocate
163 * as a result of using a cert from anchorCerts of dbList) are added
166 TPCertGroup
&certsToBeFreed
,
169 CSSM_BOOL
&verifiedToRoot
, // end of chain self-verifies
170 CSSM_BOOL
&verifiedToAnchor
, // end of chain in anchors
171 TPCertGroup
&outCertGroup
) // RETURNED
173 TPCertInfo
*subjectCert
; // the one we're working on
174 CSSM_RETURN outErr
= CSSM_OK
;
176 /* this'll be the first subject cert in the main loop */
177 subjectCert
= inCertGroup
.certAtIndex(0);
179 /* Append leaf cert to outCertGroup */
180 outCertGroup
.appendCert(subjectCert
);
181 subjectCert
->isLeaf(true);
182 outCertGroup
.setAllUnused();
184 outErr
= outCertGroup
.buildCertGroup(
194 NULL
, // gatheredCerts - none here
195 CSSM_TRUE
, // subjectIsInGroup - enables root check on
201 CssmError::throwMe(outErr
);
204 /*-----------------------------------------------------------------------------
208 * -- Construct a cert chain using TP_CertGroupConstruct.
209 * -- Attempt to verify that cert chain against one of the known
210 * good certs passed in AnchorCerts.
211 * -- Optionally enforces additional policies (TBD) when verifying the cert chain.
212 * -- Optionally returns the entire cert chain constructed in
213 * TP_CertGroupConstruct and here, all the way to an anchor cert or as
214 * far as we were able to go, in *Evidence.
217 * Two handles - to an open CL and CSP. The CSP must be capable of
218 * dealing with the signature algorithms used by the certs. The CL must be
221 * RawCerts, an unordered array of raw certs in the form of a
222 * CSSM_CERTGROUP_PTR. The first cert of this list is the subject cert
223 * which is eventually to be verified. The other certs can be in any order
224 * and may not even have any relevance to the cert chain being constructed.
225 * They may also be invalid certs.
227 * DBList, a list of DB/DL handles which may contain certs necessary to
228 * complete the desired cert chain. (Currently not implemented.)
230 * AnchorCerts, a list of known trusted certs.
231 * NumberOfAnchorCerts, size of AnchorCerts array.
233 * PolicyIdentifiers, Optional policy OID. NULL indicates default
234 * X.509 trust policy.
236 * Supported Policies:
237 * CSSMOID_APPLE_ISIGN
238 * CSSMOID_APPLE_X509_BASIC
240 * For both of these, the associated FieldValue must be {0, NULL},
242 * NumberOfPolicyIdentifiers, size of PolicyIdentifiers array, must be
245 * All other arguments must be zero/NULL.
248 * CSSM_OK : cert chain verified all the way back to an AnchorCert.
249 * CSSMERR_TP_INVALID_ANCHOR_CERT : In this case, the cert chain
250 * was validated back to a self-signed (root) cert found in either
251 * CertToBeVerified or in one of the DBs in DBList, but that root cert
252 * was *NOT* found in the AnchorCert list.
253 * CSSMERR_TP_NOT_TRUSTED: no root cert was found and no AnchorCert
254 * verified the end of the constructed cert chain.
255 * CSSMERR_TP_VERIFICATION_FAILURE: a root cert was found which does
257 * CSSMERR_TP_VERIFY_ACTION_FAILED: indicates a failure of the requested
259 * CSSMERR_TP_INVALID_CERTIFICATE: indicates a bad leaf cert.
260 * CSSMERR_TP_INVALID_REQUEST_INPUTS : no incoming VerifyContext.
261 * CSSMERR_TP_CERT_EXPIRED and CSSMERR_TP_CERT_NOT_VALID_YET: see comments
262 * for CertGroupConstruct.
263 * CSSMERR_TP_CERTIFICATE_CANT_OPERATE : issuer cert was found with a partial
264 * public key, rendering full verification impossible.
265 * CSSMERR_TP_INVALID_CERT_AUTHORITY : issuer cert was found with a partial
266 * public key and which failed to perform subsequent signature
268 *---------------------------------------------------------------------------*/
270 void AppleTPSession::CertGroupVerify(CSSM_CL_HANDLE clHand
,
271 CSSM_CSP_HANDLE cspHand
,
272 const CSSM_CERTGROUP
&CertGroupToBeVerified
,
273 const CSSM_TP_VERIFY_CONTEXT
*VerifyContext
,
274 CSSM_TP_VERIFY_CONTEXT_RESULT_PTR VerifyContextResult
)
276 CSSM_BOOL verifiedToRoot
= CSSM_FALSE
;
277 CSSM_BOOL verifiedToAnchor
= CSSM_FALSE
;
278 CSSM_RETURN constructReturn
= CSSM_OK
;
279 CSSM_RETURN policyReturn
= CSSM_OK
;
280 const CSSM_TP_CALLERAUTH_CONTEXT
*cred
;
281 CSSM_BOOL allowExpired
= CSSM_FALSE
;
282 CSSM_BOOL allowExpiredRoot
= CSSM_FALSE
;
283 /* declare volatile as compiler workaround to avoid caching in CR4 */
284 const CSSM_APPLE_TP_ACTION_DATA
* volatile actionData
= NULL
;
285 CSSM_TIMESTRING cssmTimeStr
;
286 CSSM_APPLE_TP_ACTION_FLAGS actionFlags
= 0;
287 CSSM_TP_STOP_ON tpStopOn
= 0;
289 /* keep track of whether we did policy checking; if not, we do defaults */
290 bool didCertPolicy
= false;
291 bool didRevokePolicy
= false;
293 if(VerifyContextResult
) {
294 memset(VerifyContextResult
, 0, sizeof(*VerifyContextResult
));
297 /* verify input args, skipping the ones checked by CertGroupConstruct */
298 if((VerifyContext
== NULL
) || (VerifyContext
->Cred
== NULL
)) {
299 /* the spec says that this is optional but we require it */
300 CssmError::throwMe(CSSMERR_TP_INVALID_REQUEST_INPUTS
);
302 cred
= VerifyContext
->Cred
;
304 /* Optional ActionData affecting all policies */
305 actionData
= (CSSM_APPLE_TP_ACTION_DATA
* volatile)VerifyContext
->ActionData
.Data
;
306 if(actionData
!= NULL
) {
307 switch(actionData
->Version
) {
308 case CSSM_APPLE_TP_ACTION_VERSION
:
309 if(VerifyContext
->ActionData
.Length
!=
310 sizeof(CSSM_APPLE_TP_ACTION_DATA
)) {
311 CssmError::throwMe(CSSMERR_TP_INVALID_ACTION_DATA
);
314 /* handle backwards versions here if we ever go beyond version 0 */
316 CssmError::throwMe(CSSMERR_TP_INVALID_ACTION_DATA
);
318 actionFlags
= actionData
->ActionFlags
;
319 if(actionFlags
& CSSM_TP_ACTION_ALLOW_EXPIRED
) {
320 allowExpired
= CSSM_TRUE
;
322 if(actionData
->ActionFlags
& CSSM_TP_ACTION_ALLOW_EXPIRED_ROOT
) {
323 allowExpiredRoot
= CSSM_TRUE
;
327 /* optional, may be NULL */
328 cssmTimeStr
= cred
->VerifyTime
;
330 tpStopOn
= cred
->VerificationAbortOn
;
332 /* the only two we support */
333 case CSSM_TP_STOP_ON_NONE
:
334 case CSSM_TP_STOP_ON_FIRST_FAIL
:
336 /* default maps to stop on first fail */
337 case CSSM_TP_STOP_ON_POLICY
:
338 tpStopOn
= CSSM_TP_STOP_ON_FIRST_FAIL
;
341 CssmError::throwMe(CSSMERR_TP_INVALID_STOP_ON_POLICY
);
344 /* now the args we can't deal with */
345 if(cred
->CallerCredentials
!= NULL
) {
346 CssmError::throwMe(CSSMERR_TP_INVALID_CALLERAUTH_CONTEXT_POINTER
);
350 /* get verified (possibly partial) outCertGroup - error is fatal */
351 /* BUT: we still return partial evidence if asked to...from now on. */
352 TPCertGroup
outCertGroup(*this,
353 TGO_Caller
); // certs are owned by inCertGroup
354 TPCertGroup
inCertGroup(CertGroupToBeVerified
, clHand
, cspHand
, *this,
355 cssmTimeStr
, // optional 'this' time
356 true, // firstCertMustBeValid
359 /* set up for disposal of TPCertInfos created by CertGroupConstructPriv */
360 TPCertGroup
certsToBeFreed(*this, TGO_Group
);
363 CertGroupConstructPriv(
369 cred
->NumberOfAnchorCerts
,
377 catch(const CssmError
&cerr
) {
378 constructReturn
= cerr
.cssmError();
379 /* abort if no certs found */
380 if(outCertGroup
.numCerts() == 0) {
381 CssmError::throwMe(constructReturn
);
383 /* else press on, collecting as much info as we can */
385 /* others are way fatal */
386 assert(outCertGroup
.numCerts() >= 1);
388 /* Infer interim status from return values */
389 if((constructReturn
!= CSSMERR_TP_CERTIFICATE_CANT_OPERATE
) &&
390 (constructReturn
!= CSSMERR_TP_INVALID_CERT_AUTHORITY
)) {
391 /* these returns do not get overridden */
392 if(verifiedToAnchor
) {
393 /* full success; anchor doesn't have to be root */
394 constructReturn
= CSSM_OK
;
396 else if(verifiedToRoot
) {
397 /* verified to root which is not an anchor */
398 constructReturn
= CSSMERR_TP_INVALID_ANCHOR_CERT
;
401 /* partial chain, no root, not verifiable by anchor */
402 constructReturn
= CSSMERR_TP_NOT_TRUSTED
;
407 * CSSMERR_TP_NOT_TRUSTED and CSSMERR_TP_INVALID_ANCHOR_CERT
408 * are both special cases which can result in full success
409 * when CSSM_TP_USE_INTERNAL_ROOT_CERTS is enabled.
411 #if TP_ROOT_CERT_ENABLE
412 if(actionFlags
& CSSM_TP_USE_INTERNAL_ROOT_CERTS
) {
413 // The secret "enable root cert check" flag
415 TPCertInfo
*lastCert
= outCertGroup
.lastCert();
416 if(constructReturn
== CSSMERR_TP_NOT_TRUSTED
) {
418 * See if last (non-root) cert can be verified by
419 * an embedded root */
420 assert(lastCert
!= NULL
);
421 CSSM_BOOL brtn
= tp_verifyWithKnownRoots(clHand
,
425 /* success with no incoming root, actually common (successful) case */
426 constructReturn
= CSSM_OK
;
429 else if(constructReturn
== CSSMERR_TP_INVALID_ANCHOR_CERT
) {
430 /* is the end cert the same as one of our trusted roots? */
431 assert(lastCert
!= NULL
);
432 bool brtn
= tp_isKnownRootCert(lastCert
, clHand
);
434 constructReturn
= CSSM_OK
;
438 #endif /* TP_ROOT_CERT_ENABLE */
441 * Parameters passed to tp_policyVerify() and which vary per policy
445 const CSSM_APPLE_TP_SSL_OPTIONS
*sslOpts
;
446 CSSM_RETURN thisPolicyRtn
= CSSM_OK
; // returned from tp_policyVerify()
448 /* common CRL verify parameters */
449 TPCrlGroup
*crlGroup
= NULL
;
451 crlGroup
= new TPCrlGroup(&VerifyContext
->Crls
,
457 catch(const CssmError
&cerr
) {
458 CSSM_RETURN cr
= cerr
.cssmError();
459 /* I don't see a straightforward way to report this error,
460 * other than adding it to the leaf cert's status... */
461 outCertGroup
.certAtIndex(0)->addStatusCode(cr
);
462 tpDebug("CertGroupVerify: error constructing CrlGroup; continuing\n");
464 /* others are way fatal */
466 TPCrlVerifyContext
crlVfyContext(*this,
470 cred
->NumberOfAnchorCerts
,
475 * This may consist of certs gathered from the net (which is the purpose
476 * of this argument) and from DLDBs (a side-effect optimization).
480 kCrlNone
, // policy, varies per policy
482 0); // crlOptFlags, varies per policy
484 /* true if we're to execute tp_policyVerify at end of loop */
487 /* grind thru each policy */
488 for(uint32 polDex
=0; polDex
<cred
->Policy
.NumberOfPolicyIds
; polDex
++) {
489 if(cred
->Policy
.PolicyIds
== NULL
) {
490 policyReturn
= CSSMERR_TP_INVALID_POLICY_IDENTIFIERS
;
493 CSSM_FIELD_PTR policyId
= &cred
->Policy
.PolicyIds
[polDex
];
494 const CSSM_DATA
*fieldVal
= &policyId
->FieldValue
;
495 const CSSM_OID
*oid
= &policyId
->FieldOid
;
496 thisPolicyRtn
= CSSM_OK
;
497 doPolicyVerify
= false;
500 /* first the basic cert policies */
501 if(tpCompareOids(oid
, &CSSMOID_APPLE_TP_SSL
)) {
503 doPolicyVerify
= true;
504 /* and do the tp_policyVerify() call below */
507 else if(tpCompareOids(oid
, &CSSMOID_APPLE_X509_BASIC
)) {
509 if(fieldVal
->Data
!= NULL
) {
510 policyReturn
= CSSMERR_TP_INVALID_POLICY_IDENTIFIERS
;
513 tpPolicy
= kTPx509Basic
;
514 doPolicyVerify
= true;
517 else if(tpCompareOids(oid
, &CSSMOID_APPLE_TP_SMIME
)) {
518 tpPolicy
= kTP_SMIME
;
519 doPolicyVerify
= true;
522 else if(tpCompareOids(oid
, &CSSMOID_APPLE_TP_EAP
)) {
523 /* treated here exactly the same as SSL */
525 doPolicyVerify
= true;
528 else if(tpCompareOids(oid
, &CSSMOID_APPLE_ISIGN
)) {
530 if(fieldVal
->Data
!= NULL
) {
531 policyReturn
= CSSMERR_TP_INVALID_POLICY_IDENTIFIERS
;
535 doPolicyVerify
= true;
538 /* now revocation policies */
539 else if(tpCompareOids(oid
, &CSSMOID_APPLE_TP_REVOCATION_CRL
)) {
540 /* CRL-specific options */
541 const CSSM_APPLE_TP_CRL_OPTIONS
*crlOpts
;
542 crlOpts
= (CSSM_APPLE_TP_CRL_OPTIONS
*)fieldVal
->Data
;
543 thisPolicyRtn
= CSSM_OK
;
544 if(crlOpts
!= NULL
) {
545 switch(crlOpts
->Version
) {
546 case CSSM_APPLE_TP_CRL_OPTS_VERSION
:
547 if(fieldVal
->Length
!=
548 sizeof(CSSM_APPLE_TP_CRL_OPTIONS
)) {
550 CSSMERR_TP_INVALID_POLICY_IDENTIFIERS
;
554 /* handle backwards compatibility here if necessary */
556 thisPolicyRtn
= CSSMERR_TP_INVALID_POLICY_IDENTIFIERS
;
559 if(thisPolicyRtn
!= CSSM_OK
) {
560 policyReturn
= thisPolicyRtn
;
564 crlVfyContext
.policy
= kCrlBasic
;
565 crlVfyContext
.crlOpts
= crlOpts
;
567 thisPolicyRtn
= tpVerifyCertGroupWithCrls(outCertGroup
,
569 didRevokePolicy
= true;
571 /* etc. - add more policies here */
573 /* unknown TP policy OID */
574 policyReturn
= CSSMERR_TP_INVALID_POLICY_IDENTIFIERS
;
578 /* common tp_policyVerify call */
580 thisPolicyRtn
= tp_policyVerify(tpPolicy
,
588 cred
->Policy
.PolicyControl
); // not currently used
589 didCertPolicy
= true;
593 /* Policy error. First remember the error if it's the first policy
594 * error we'veĆseen. */
595 if(policyReturn
== CSSM_OK
) {
596 policyReturn
= thisPolicyRtn
;
599 if(tpStopOn
== CSSM_TP_STOP_ON_FIRST_FAIL
) {
600 /* Nope; we're done with policy evaluation */
604 } /* for each policy */
607 * Upon completion of the above loop, perform default policy ops if
610 if((policyReturn
== CSSM_OK
) || (tpStopOn
== CSSM_TP_STOP_ON_NONE
)) {
612 policyReturn
= tp_policyVerify(kTPDefault
,
619 NULL
, // policyFieldData
620 cred
->Policy
.PolicyControl
); // not currently used
622 if( !didRevokePolicy
&& // no revoke policy yet
623 ( (policyReturn
== CSSM_OK
|| // default cert policy OK
624 (tpStopOn
== CSSM_TP_STOP_ON_NONE
)) // keep going anyway
628 crlVfyContext
.policy
= TP_CRL_POLICY_DEFAULT
;
629 crlVfyContext
.crlOpts
= NULL
;
630 CSSM_RETURN thisPolicyRtn
= tpVerifyCertGroupWithCrls(outCertGroup
,
632 if((thisPolicyRtn
!= CSSM_OK
) && (policyReturn
== CSSM_OK
)) {
633 policyReturn
= thisPolicyRtn
;
637 } /* default policy opts */
641 /* return evidence - i.e., constructed chain - if asked to */
642 if(VerifyContextResult
!= NULL
) {
644 * VerifyContextResult->Evidence[0] : CSSM_TP_APPLE_EVIDENCE_HEADER
645 * VerifyContextResult->Evidence[1] : CSSM_CERTGROUP
646 * VerifyContextResult->Evidence[2] : CSSM_TP_APPLE_EVIDENCE_INFO
648 VerifyContextResult
->NumberOfEvidences
= 3;
649 VerifyContextResult
->Evidence
=
650 (CSSM_EVIDENCE_PTR
)calloc(3, sizeof(CSSM_EVIDENCE
));
652 CSSM_TP_APPLE_EVIDENCE_HEADER
*hdr
=
653 (CSSM_TP_APPLE_EVIDENCE_HEADER
*)malloc(
654 sizeof(CSSM_TP_APPLE_EVIDENCE_HEADER
));
655 hdr
->Version
= CSSM_TP_APPLE_EVIDENCE_VERSION
;
656 CSSM_EVIDENCE_PTR ev
= &VerifyContextResult
->Evidence
[0];
657 ev
->EvidenceForm
= CSSM_EVIDENCE_FORM_APPLE_HEADER
;
660 ev
= &VerifyContextResult
->Evidence
[1];
661 ev
->EvidenceForm
= CSSM_EVIDENCE_FORM_APPLE_CERTGROUP
;
662 ev
->Evidence
= outCertGroup
.buildCssmCertGroup();
664 ev
= &VerifyContextResult
->Evidence
[2];
665 ev
->EvidenceForm
= CSSM_EVIDENCE_FORM_APPLE_CERT_INFO
;
666 ev
->Evidence
= outCertGroup
.buildCssmEvidenceInfo();
669 CSSM_RETURN outErr
= outCertGroup
.getReturnCode(constructReturn
,
670 allowExpired
, allowExpiredRoot
, policyReturn
);
673 CssmError::throwMe(outErr
);