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