]> git.saurik.com Git - apple/security.git/blob - AppleX509TP/tpCertGroup.cpp
Security-29.tar.gz
[apple/security.git] / AppleX509TP / tpCertGroup.cpp
1 /*
2 * Copyright (c) 2000-2001 Apple Computer, 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 obtain
7 * a copy of the License at http://www.apple.com/publicsource and read it before
8 * 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 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.
16 */
17
18
19 /*
20 * tpCertGroup.cpp - Cert group functions (construct, verify)
21 *
22 * Created 10/5/2000 by Doug Mitchell.
23 */
24
25 #include "AppleTPSession.h"
26 #include "certGroupUtils.h"
27 #include "TPCertInfo.h"
28 #include "tpPolicies.h"
29 #include "tpdebugging.h"
30 #include <Security/oidsalg.h>
31
32
33 /*-----------------------------------------------------------------------------
34 * CertGroupConstruct
35 *
36 * Description:
37 * This function returns a pointer to a mallocd CSSM_CERTGROUP which
38 * refers to a mallocd list of raw ordered X.509 certs which verify back as
39 * far as the TP is able to go. The first cert of the returned list is the
40 * subject cert. The TP will attempt to search thru the DBs passed in
41 * DBList in order to complete the chain. The chain is completed when a
42 * self-signed (root) cert is found in the chain. The root cert may be
43 * present in the input CertGroupFrag, or it may have been obtained from
44 * one of the DBs passed in DBList. It is not an error if no root cert is
45 * found.
46 *
47 * The error conditions are:
48 * -- The first cert of CertGroupFrag is an invalid cert. NULL is returned,
49 * err = CSSM_TP_INVALID_CERTIFICATE.
50 * -- The root cert (if found) fails to verify. Valid certgroup is returned,
51 * err = CSSMERR_TP_VERIFICATION_FAILURE.
52 * -- Any cert in the (possibly partially) constructed chain has expired or
53 * isn't valid yet, err = CSSMERR_TP_CERT_EXPIRED or
54 * CSSMERR_TP_CERT_NOT_VALID_YET. A CertGroup is returned.
55 * -- CSSMERR_TP_CERT_EXPIRED and CSSMERR_TP_CERT_NOT_VALID_YET. If one of these
56 * conditions obtains for the first (leaf) cert, the function throws this
57 * error immediately and the outgoing cert group is empty. For subsequent certs,
58 * the temporal validity of a cert is only tested AFTER a cert successfully
59 * meets the cert chaining criteria (subject/issuer match and signature
60 * verify). A cert in a chain with this error is not added to the outgoing
61 * cert group.
62 * -- the usual errors like bad handle or memory failure.
63 *
64 * Parameters:
65 * Two handles - to an open CL and CSP. The CSP must be capable of
66 * dealing with the signature algorithms used by the certs. The CL must be
67 * an X.509-savvy CL.
68 *
69 * CertGroupFrag, an unordered array of raw X.509 certs in the form of a
70 * CSSM_CERTGROUP_PTR. The first cert of this list is the subject cert
71 * which is eventually to be verified. The other certs can be in any order
72 * and may not even have any relevance to the cert chain being constructed.
73 * They may also be invalid certs.
74 *
75 * DBList, a list of DB/DL handles which may contain certs necessary to
76 * complete the desired cert chain. (Not currently implemented.)
77 *
78 *---------------------------------------------------------------------------*/
79
80 /* public version */
81 void AppleTPSession::CertGroupConstruct(CSSM_CL_HANDLE clHand,
82 CSSM_CSP_HANDLE cspHand,
83 const CSSM_DL_DB_LIST &DBList,
84 const void *ConstructParams,
85 const CSSM_CERTGROUP &CertGroupFrag,
86 CSSM_CERTGROUP_PTR &CertGroup)
87 {
88 TPCertGroup *tpCertGroup;
89 CertGroupConstructPriv(clHand,
90 cspHand,
91 DBList,
92 ConstructParams,
93 CertGroupFrag,
94 CSSM_FALSE, // allowExpired
95 tpCertGroup);
96 CertGroup = tpCertGroup->buildCssmCertGroup();
97 delete tpCertGroup;
98 }
99
100
101 /*
102 * Private version of CertGroupConstruct, used by CertGroupConstruct and
103 * CertGroupVerify. Returns a TP-style TPCertGroup for further processing.
104 * This only throws CSSM-style exceptions in the following cases:
105 *
106 * -- input parameter errors
107 * -- the first (leaf) cert is bad (doesn't parse, expired, not valid yet).
108 *
109 * All other cert-related errors simply result in the bad cert being ignored.
110 * Other exceptions are gross system errors like malloc failure.
111 */
112 void AppleTPSession::CertGroupConstructPriv(CSSM_CL_HANDLE clHand,
113 CSSM_CSP_HANDLE cspHand,
114 const CSSM_DL_DB_LIST &DBList,
115 const void *ConstructParams,
116 const CSSM_CERTGROUP &CertGroupFrag,
117 CSSM_BOOL allowExpired,
118 TPCertGroup *&CertGroup)
119 {
120 TPCertGroup *inCertGroup; // unordered input certs
121 TPCertGroup *outCertGroup; // ordered, verified output certs
122
123 /*
124 * subjectCert refers to the cert we're currently trying to verify. It's either
125 * an element in inCertGroup (if we're verifying a cert from the incoming
126 * CertGroupFrag) or dbSubject (if we're verifying a cert which came from a DB).
127 *
128 * Similarly, issuerCert, when non-NULL, points to a cert which has just
129 * been located as a verifiable issuer of subjectCert. It points to either
130 * an element in inCertGroup or to dbIssuer.
131 */
132 TPCertInfo *subjectCert; // the one we're working on
133 TPCertInfo *issuerCert = NULL; // verified as next one in chain
134 TPCertInfo *certInfo; // working cert
135 unsigned certDex; // index into certInfo
136 CSSM_RETURN crtn;
137 CSSM_RETURN outErr = CSSM_OK;
138
139 /* verify input args */
140 if(cspHand == CSSM_INVALID_HANDLE) {
141 CssmError::throwMe(CSSMERR_TP_INVALID_CSP_HANDLE);
142 }
143 if(clHand == CSSM_INVALID_HANDLE) {
144 CssmError::throwMe(CSSMERR_TP_INVALID_CL_HANDLE);
145 }
146 if( (CertGroupFrag.NumCerts == 0) || // list is empty
147 (CertGroupFrag.CertGroupType != CSSM_CERTGROUP_ENCODED_CERT) ||
148 (CertGroupFrag.GroupList.CertList[0].Data == NULL) || // first cert empty
149 (CertGroupFrag.GroupList.CertList[0].Length == 0)) { // first cert empty
150 CssmError::throwMe(CSSMERR_CL_INVALID_CERTGROUP_POINTER);
151 }
152 switch(CertGroupFrag.CertType) {
153 case CSSM_CERT_X_509v1:
154 case CSSM_CERT_X_509v2:
155 case CSSM_CERT_X_509v3:
156 break;
157 default:
158 CssmError::throwMe(CSSMERR_TP_UNKNOWN_FORMAT);
159 }
160 switch(CertGroupFrag.CertEncoding) {
161 case CSSM_CERT_ENCODING_BER:
162 case CSSM_CERT_ENCODING_DER:
163 break;
164 default:
165 CssmError::throwMe(CSSMERR_TP_UNKNOWN_FORMAT);
166 }
167
168 /*
169 * Set up incoming and outgoing TPCertGrorups.
170 */
171 inCertGroup = new TPCertGroup(*this, CertGroupFrag.NumCerts - 1);
172 outCertGroup = new TPCertGroup(*this, CertGroupFrag.NumCerts);
173
174 /*
175 * Parse first (leaf) cert. Note that this cert is special: if it's bad we abort
176 * immediately; otherwise it goes directly into outCertGroup.
177 */
178 try {
179 certInfo = new TPCertInfo(
180 &CertGroupFrag.GroupList.CertList[0],
181 clHand);
182 }
183 catch(CssmError cerr) {
184 outErr = CSSMERR_TP_INVALID_CERTIFICATE;
185 goto abort;
186 }
187 catch(...) {
188 /* everything else is way fatal */
189 throw;
190 }
191
192 /* verify this first one is current */
193 outErr = certInfo->isCurrent(allowExpired);
194 if(outErr) {
195 goto abort;
196 }
197
198 /* Add to outCertGroup */
199 outCertGroup->appendCert(certInfo);
200
201 /* this'll be the first subject cert in the main loop */
202 subjectCert = certInfo;
203
204 /*
205 * Add remaining input certs to inCertGroup. Note that this lets us
206 * skip bad incoming certs right away.
207 */
208 for(certDex=1; certDex<CertGroupFrag.NumCerts; certDex++) {
209 try {
210 certInfo = new TPCertInfo(&CertGroupFrag.GroupList.CertList[certDex],
211 clHand);
212 }
213 catch (...) {
214 /* just ignore this cert */
215 continue;
216 }
217 inCertGroup->appendCert(certInfo);
218 }
219
220 /*** main loop ***
221 *
222 * On entry, we have two TPCertGroups. InCertGroup contains n-1 certs, where n
223 * is the size of the CertGroupFrag passed to us by the caller. The certs in
224 * inCertGroup are unordered but are known to be parseable, CL-cacheable certs.
225 * OutGroupCert contains one cert, the incoming leaf cert.
226 *
227 * The job in this loop is to build an ordered, verified cert chain in
228 * outCertGroup out of certs from inCertGroup and/or DBList. As good certs
229 * are found in inCertGroup, they're removed from that TPCertGroup. On exit
230 * we delete inCertGroup, which deletes all the remaining TPCertInfo's in it.
231 * The constructed outCertGroup is returned to the caller.
232 *
233 * Exit loop on:
234 * -- find a root cert in the chain
235 * -- memory error
236 * -- or no more certs to add to chain.
237 */
238 for(;;) {
239 /* top of loop: subjectCert is the cert we're trying to verify. */
240
241 /* is this a root cert? */
242 if(subjectCert->isSelfSigned()) {
243 /*
244 * Verify this alleged root cert. We're at the end of the chain no
245 * matter what happens here.
246 * Note we already validated before/after when this was tested
247 * as issuer (or, if it's the leaf cert, before we entered this loop).
248 */
249 outErr = tp_VerifyCert(clHand,
250 cspHand,
251 subjectCert,
252 subjectCert,
253 CSSM_FALSE, // checkIssuerCurrent
254 CSSM_TRUE); // allowExpired, don't care
255 break;
256 }
257
258 /* Search unused incoming certs to find an issuer */
259 for(certDex=0; certDex<inCertGroup->numCerts(); certDex++) {
260 certInfo = inCertGroup->certAtIndex(certDex);
261
262 /* potential issuer - names match? */
263 if(tpIsSameName(subjectCert->issuerName(), certInfo->subjectName())) {
264 /* yep, do a sig verify with "not before/after" check */
265 crtn = tp_VerifyCert(clHand,
266 cspHand,
267 subjectCert,
268 certInfo,
269 CSSM_TRUE,
270 allowExpired);
271 switch(crtn) {
272 case CSSM_OK:
273 /* YES! We'll add it to outCertGroup below...*/
274 issuerCert = certInfo;
275 inCertGroup->removeCertAtIndex(certDex);
276 goto issuerLoopEnd;
277 case CSSMERR_TP_CERT_NOT_VALID_YET:
278 case CSSMERR_TP_CERT_EXPIRED:
279 /* special case - abort immediateley (note the cert
280 * sig verify succeeded.) */
281 outErr = crtn;
282 goto abort;
283 default:
284 /* just skip this one and keep looking */
285 break;
286 }
287 } /* names match */
288 } /* searching inCertGroup for issuer */
289
290 issuerLoopEnd:
291
292 #if TP_DL_ENABLE
293 if(issuerCert == NULL) {
294 /* Issuer not in incoming cert group. Search DBList. */
295 CSSM_DATA_PTR foundCert;
296
297 foundCert = tpFindIssuer(tpHand,
298 clHand,
299 cspHand,
300 subjectCert->certData(),
301 subjectCert->issuerName(),
302 DBList,
303 &subjectExpired);
304 if(subjectExpired) {
305 /* special case - abort immediately */
306 outErr = subjectExpired;
307 goto abort;
308 }
309 if(foundCert != NULL) {
310 /* set issuerCert for this found cert */
311 issuerCert = new TPCertInfo(foundCert,
312 clHand,
313 true); // *do* copy
314 /*
315 * free cert data obtained from DB
316 * FIXME: this assumes that OUR session allocators are the
317 * same ones used by the DL to malloc this cert!
318 * FIXME: handle exception here
319 */
320 tpFreeCssmData(*this, foundCert, CSSM_TRUE);
321 }
322 } /* Issuer not in incoming cert group */
323 #endif /* TP_DL_ENABLE */
324
325 if(issuerCert == NULL) {
326 /* end of search, broken chain */
327 break;
328 }
329
330 /*
331 * One way or the other, we've found a cert which verifies subjectCert.
332 * Add the issuer to outCertGroup and make it the new subjectCert for
333 * the next pass.
334 */
335 outCertGroup->appendCert(issuerCert);
336 subjectCert = issuerCert;
337 issuerCert = NULL;
338 } /* main loop */
339
340 abort:
341 delete inCertGroup;
342 CertGroup = outCertGroup;
343 if(outErr) {
344 CssmError::throwMe(outErr);
345 }
346 }
347 /*-----------------------------------------------------------------------------
348 * CertGroupVerify
349 *
350 * Description:
351 * -- Construct a cert chain using TP_CertGroupConstruct.
352 * -- Attempt to verify that cert chain against one of the known
353 * good certs passed in AnchorCerts.
354 * -- Optionally enforces additional policies (TBD) when verifying the cert chain.
355 * -- Optionally returns the entire cert chain constructed in
356 * TP_CertGroupConstruct and here, all the way to an anchor cert or as
357 * far as we were able to go, in *Evidence.
358 *
359 * Parameters:
360 * Two handles - to an open CL and CSP. The CSP must be capable of
361 * dealing with the signature algorithms used by the certs. The CL must be
362 * an X.509-savvy CL.
363 *
364 * RawCerts, an unordered array of raw certs in the form of a
365 * CSSM_CERTGROUP_PTR. The first cert of this list is the subject cert
366 * which is eventually to be verified. The other certs can be in any order
367 * and may not even have any relevance to the cert chain being constructed.
368 * They may also be invalid certs.
369 *
370 * DBList, a list of DB/DL handles which may contain certs necessary to
371 * complete the desired cert chain. (Currently not implemented.)
372 *
373 * AnchorCerts, a list of known trusted certs.
374 * NumberOfAnchorCerts, size of AnchorCerts array.
375 *
376 * PolicyIdentifiers, Optional policy OID. NULL indicates default
377 * X.509 trust policy.
378 *
379 * Supported Policies:
380 * CSSMOID_APPLE_ISIGN
381 * CSSMOID_APPLE_X509_BASIC
382 *
383 * For both of these, the associated FieldValue must be {0, NULL},
384 *
385 * NumberOfPolicyIdentifiers, size of PolicyIdentifiers array, must be
386 * zero or one.
387 *
388 * All other arguments must be zero/NULL.
389 *
390 * Returns:
391 * CSSM_OK : cert chain verified all the way back to an AnchorCert.
392 * CSSMERR_TP_INVALID_ANCHOR_CERT : In this case, the cert chain
393 * was validated back to a self-signed (root) cert found in either
394 * CertToBeVerified or in one of the DBs in DBList, but that root cert
395 * was *NOT* found in the AnchorCert list.
396 * CSSMERR_TP_NOT_TRUSTED: no root cert was found and no AnchorCert
397 * verified the end of the constructed cert chain.
398 * CSSMERR_TP_VERIFICATION_FAILURE: a root cert was found which does
399 * not self-verify.
400 * CSSMERR_TP_VERIFY_ACTION_FAILED: indicates a failure of the requested
401 * policy action.
402 * CSSMERR_TP_INVALID_CERTIFICATE: indicates a bad leaf cert.
403 * CSSMERR_TP_INVALID_REQUEST_INPUTS : no incoming VerifyContext.
404 * CSSMERR_TP_CERT_EXPIRED and CSSMERR_TP_CERT_NOT_VALID_YET: see comments
405 * for CertGroupConstruct.
406 *---------------------------------------------------------------------------*/
407
408 void AppleTPSession::CertGroupVerify(CSSM_CL_HANDLE clHand,
409 CSSM_CSP_HANDLE cspHand,
410 const CSSM_CERTGROUP &CertGroupToBeVerified,
411 const CSSM_TP_VERIFY_CONTEXT *VerifyContext,
412 CSSM_TP_VERIFY_CONTEXT_RESULT_PTR VerifyContextResult)
413 {
414 unsigned i;
415 TPCertInfo *lastCert;
416 CSSM_BOOL verifiedToRoot = CSSM_FALSE;
417 TPPolicy policy;
418 CSSM_RETURN outErr = CSSM_OK;
419 CSSM_RETURN crtn;
420 const CSSM_TP_CALLERAUTH_CONTEXT *cred;
421 CSSM_OID_PTR oid = NULL;
422 CSSM_BOOL allowExpired = CSSM_FALSE;
423 TPCertGroup *tpCertGroup = NULL; // created by
424 // CertGroupConstructPriv
425 TPCertInfo *certInfo = NULL;
426
427 /* verify input args, skipping the ones checked by CertGroupConstruct */
428 if((VerifyContext == NULL) || (VerifyContext->Cred == NULL)) {
429 /* the spec says that this is optional but we require it */
430 CssmError::throwMe(CSSMERR_TP_INVALID_REQUEST_INPUTS);
431 }
432 cred = VerifyContext->Cred;
433
434 /* allow cert expiration errors? */
435 if(cred->Policy.PolicyControl == CSSM_TP_ALLOW_EXPIRE) {
436 allowExpired = CSSM_TRUE;
437 }
438
439 /* Check out requested policies */
440 switch(cred->Policy.NumberOfPolicyIds) {
441 case 0:
442 /* default */
443 policy = kTPDefault;
444 break;
445 case 1:
446 if(cred->Policy.PolicyIds == NULL) {
447 CssmError::throwMe(CSSMERR_TP_INVALID_POLICY_IDENTIFIERS);
448 }
449
450 /*
451 * none of the supported policies allow any additional params
452 */
453 if((cred->Policy.PolicyIds->FieldValue.Data != NULL) ||
454 (cred->Policy.PolicyIds->FieldValue.Length != 0)) {
455 CssmError::throwMe(CSSMERR_TP_INVALID_POLICY_IDENTIFIERS);
456 }
457 oid = &cred->Policy.PolicyIds->FieldOid;
458 if(tpCompareOids(oid, &CSSMOID_APPLE_ISIGN)) {
459 policy = kTPiSign;
460 }
461 else if(tpCompareOids(oid, &CSSMOID_APPLE_X509_BASIC)) {
462 policy = kTPx509Basic;
463 }
464 else if(tpCompareOids(oid, &CSSMOID_APPLE_TP_SSL)) {
465 policy = kTP_SSL;
466 }
467 else {
468 /* unknown TP OID */
469 CssmError::throwMe(CSSMERR_TP_INVALID_POLICY_IDENTIFIERS);
470 }
471 break;
472 default:
473 /* only zero or one allowed */
474 CssmError::throwMe(CSSMERR_TP_INVALID_POLICY_IDENTIFIERS);
475 }
476
477 /* now the args we can't deal with */
478 if(cred->CallerCredentials != NULL) {
479 CssmError::throwMe(CSSMERR_TP_INVALID_CALLERAUTH_CONTEXT_POINTER);
480 }
481 /* FIXME - ANY OTHERS? */
482
483 /* get verified (possibly partial) outCertGroup - error is fatal */
484 /* BUT: we still return partial evidence if asked to...from now on. */
485 try {
486 CertGroupConstructPriv(
487 clHand,
488 cspHand,
489 *cred->DBList, // not optional to Construct!
490 NULL,
491 CertGroupToBeVerified,
492 allowExpired,
493 tpCertGroup);
494 }
495 catch(CssmError cerr) {
496 outErr = cerr.cssmError();
497 goto out;
498 }
499 /* others are way fatal */
500 CASSERT(tpCertGroup != NULL);
501 CASSERT(tpCertGroup->numCerts() >= 1);
502
503 /* subsequent errors and returns to out: */
504
505 /*
506 * Case 1: last cert in outCertGroup is a root cert. See if
507 * the root cert is in AnchorCerts.
508 * Note that TP_CertGroupConstruct did the actual root
509 * self-verify test.
510 */
511 lastCert = tpCertGroup->lastCert();
512 if(lastCert->isSelfSigned()) {
513 verifiedToRoot = CSSM_TRUE;
514
515 /* see if that root cert is identical to one of the anchor certs */
516 for(i=0; i<cred->NumberOfAnchorCerts; i++) {
517 if(tp_CompareCerts(lastCert->certData(), &cred->AnchorCerts[i])) {
518 /* one fully successful return */
519 outErr = CSSM_OK;
520 goto out;
521 }
522 }
523
524 /* verified to a root cert which is not an anchor */
525 outErr = CSSMERR_TP_INVALID_ANCHOR_CERT;
526 goto out;
527 }
528
529 /* try to validate lastCert with anchor certs */
530 /* note we're skipping the subject/issuer check...OK? */
531 for(i=0; i<cred->NumberOfAnchorCerts; i++) {
532 try {
533 certInfo = new TPCertInfo(&cred->AnchorCerts[i],
534 clHand);
535 }
536 catch(...) {
537 /* bad anchor cert - ignore it */
538 continue;
539 }
540 crtn = tp_VerifyCert(clHand,
541 cspHand,
542 lastCert,
543 certInfo,
544 CSSM_TRUE, // check not/before of anchor
545 allowExpired);
546 switch(crtn) {
547 case CSSM_OK:
548 /* The other normal fully successful return. */
549 outErr = CSSM_OK;
550 if(certInfo->isSelfSigned()) {
551 verifiedToRoot = CSSM_TRUE;
552 }
553
554 /*
555 * One more thing: add this anchor cert to the Evidence chain
556 */
557 try {
558 tpCertGroup->appendCert(certInfo);
559 }
560 catch(...) {
561 /* shoot - must be memory error */
562 verifiedToRoot = CSSM_FALSE;
563 delete certInfo;
564 outErr = CSSMERR_TP_MEMORY_ERROR;
565 }
566 goto out;
567
568 case CSSMERR_TP_CERT_NOT_VALID_YET:
569 case CSSMERR_TP_CERT_EXPIRED:
570 /* special case - abort immediateley */
571 delete certInfo;
572 outErr = crtn;
573 goto out;
574 default:
575 /* continue to next anchor */
576 delete certInfo;
577 break;
578 }
579 } /* for each anchor */
580
581 /* partial chain, no root, not verifiable by anchor */
582 outErr = CSSMERR_TP_NOT_TRUSTED;
583
584 /* common exit - error or success */
585 out:
586 /*
587 * Do further policy verification if appropriate.
588 *
589 * SSL: CSSMERR_TP_NOT_TRUSTED and CSSMERR_TP_INVALID_ANCHOR_CERT
590 * are both special cases which can result in full success.
591 */
592 if((policy == kTP_SSL) && (outErr == CSSMERR_TP_NOT_TRUSTED)) {
593 /* see if last cert can be verified by an embedded SSL root */
594 certInfo = tpCertGroup->lastCert();
595 CSSM_BOOL brtn = tp_verifyWithSslRoots(clHand,
596 cspHand,
597 certInfo);
598 if(brtn) {
599 /* SSL success with no incoming root */
600 /* note unknown incoming root (INVALID_ANCHOR_CERT) is handled
601 * below, after tp_policyVerify */
602 outErr = CSSM_OK;
603 }
604 }
605 if((outErr == CSSM_OK) || // full success so far
606 (outErr == CSSMERR_TP_INVALID_ANCHOR_CERT)) { // OK, but root not an anchor
607
608 CSSM_RETURN crtn = tp_policyVerify(policy,
609 *this,
610 clHand,
611 cspHand,
612 tpCertGroup,
613 verifiedToRoot);
614 if(crtn) {
615 /* don't override existing INVALID_ANCHOR_CERT on policy success */
616 outErr = crtn;
617 }
618 else if((outErr == CSSMERR_TP_INVALID_ANCHOR_CERT) && (policy == kTP_SSL)) {
619 /* SSL - found a good anchor, move to full success */
620 outErr = CSSM_OK;
621 }
622 }
623
624 /* return evidence - i.e., current chain - if asked to */
625 if(VerifyContextResult != NULL) {
626 /* The spec is utterly bogus. We're going to punt and use
627 * CSSM_EVIDENCE_FORM_UNSPECIFIC to mean just a pointer to
628 * a CSSM_CERTGROUP. How's that!?
629 */
630 VerifyContextResult->NumberOfEvidences = 1;
631 VerifyContextResult->Evidence =
632 (CSSM_EVIDENCE_PTR)malloc(sizeof(CSSM_EVIDENCE));
633 VerifyContextResult->Evidence->EvidenceForm = CSSM_EVIDENCE_FORM_UNSPECIFIC;
634 VerifyContextResult->Evidence->Evidence =
635 tpCertGroup->buildCssmCertGroup();
636 }
637
638 /* delete (internaluse only) TPCertGroup */
639 delete tpCertGroup;
640 if(outErr) {
641 CssmError::throwMe(outErr);
642 }
643 }
644
645