]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_apple_x509_tp/lib/tpCertGroup.cpp
Security-59754.41.1.tar.gz
[apple/security.git] / OSX / libsecurity_apple_x509_tp / lib / tpCertGroup.cpp
1 /*
2 * Copyright (c) 2000-2001,2011-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 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
23 #include "AppleTPSession.h"
24 #include "certGroupUtils.h"
25 #include "TPCertInfo.h"
26 #include "TPCrlInfo.h"
27 #include "tpPolicies.h"
28 #include "tpdebugging.h"
29 #include "tpCrlVerify.h"
30 #include <Security/oidsalg.h>
31 #include <Security/cssmapple.h>
32
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 outCertGroup(*this, TGO_Caller);
90 TPCertGroup inCertGroup(CertGroupFrag,
91 clHand,
92 cspHand,
93 *this,
94 NULL, // cssmTimeStr
95 true, // firstCertMustBeValid
96 TGO_Group);
97
98 /* set up for disposal of TPCertInfos created by CertGroupConstructPriv */
99 TPCertGroup gatheredCerts(*this, TGO_Group);
100
101 CSSM_RETURN constructReturn = CSSM_OK;
102 CSSM_APPLE_TP_ACTION_FLAGS actionFlags = 0;
103 CSSM_BOOL verifiedToRoot; // not used
104 CSSM_BOOL verifiedToAnchor; // not used
105 CSSM_BOOL verifiedViaTrustSetting; // not used
106
107 try {
108 CertGroupConstructPriv(clHand,
109 cspHand,
110 inCertGroup,
111 &DBList,
112 NULL, // cssmTimeStr
113 /* no anchors */
114 0, NULL,
115 actionFlags,
116 /* no user trust */
117 NULL, NULL, 0, 0,
118 gatheredCerts,
119 verifiedToRoot,
120 verifiedToAnchor,
121 verifiedViaTrustSetting,
122 outCertGroup);
123 }
124 catch(const CssmError &cerr) {
125 constructReturn = cerr.error;
126 /* abort if no certs found */
127 if(outCertGroup.numCerts() == 0) {
128 CssmError::throwMe(constructReturn);
129 }
130 }
131 CertGroup = outCertGroup.buildCssmCertGroup();
132 /* caller of this function never gets evidence... */
133 outCertGroup.freeDbRecords();
134
135 if(constructReturn) {
136 CssmError::throwMe(constructReturn);
137 }
138 }
139
140
141 /*
142 * Private version of CertGroupConstruct, used by CertGroupConstruct and
143 * CertGroupVerify. Populates a TP-style TPCertGroup for further processing.
144 * This only throws CSSM-style exceptions in the following cases:
145 *
146 * -- input parameter errors
147 * -- the first (leaf) cert is bad (doesn't parse, expired, not valid yet).
148 * -- root found but it doesn't self-verify
149 *
150 * All other cert-related errors simply result in the bad cert being ignored.
151 * Other exceptions are gross system errors like malloc failure.
152 */
153 void AppleTPSession::CertGroupConstructPriv(CSSM_CL_HANDLE clHand,
154 CSSM_CSP_HANDLE cspHand,
155 TPCertGroup &inCertGroup,
156 const CSSM_DL_DB_LIST *DBList, // optional here
157 const char *cssmTimeStr, // optional
158
159 /* trusted anchors, optional */
160 /* FIXME - maybe this should be a TPCertGroup */
161 uint32 numAnchorCerts,
162 const CSSM_DATA *anchorCerts,
163
164 /* CSSM_TP_ACTION_FETCH_CERT_FROM_NET, CSSM_TP_ACTION_TRUST_SETTINGS */
165 CSSM_APPLE_TP_ACTION_FLAGS actionFlags,
166
167 /* optional user trust parameters */
168 const CSSM_OID *policyOid,
169 const char *policyStr,
170 uint32 policyStrLen,
171 SecTrustSettingsKeyUsage keyUse,
172
173 /*
174 * Certs to be freed by caller (i.e., TPCertInfo which we allocate
175 * as a result of using a cert from anchorCerts or dbList) are added
176 * to this group.
177 */
178 TPCertGroup &certsToBeFreed,
179
180 /* returned */
181 CSSM_BOOL &verifiedToRoot, // end of chain self-verifies
182 CSSM_BOOL &verifiedToAnchor, // end of chain in anchors
183 CSSM_BOOL &verifiedViaTrustSetting, // chain ends per User Trust setting
184 TPCertGroup &outCertGroup) // RETURNED
185 {
186 TPCertInfo *subjectCert; // the one we're working on
187 CSSM_RETURN outErr = CSSM_OK;
188
189 /* this'll be the first subject cert in the main loop */
190 subjectCert = inCertGroup.certAtIndex(0);
191
192 /* Append leaf cert to outCertGroup */
193 outCertGroup.appendCert(subjectCert);
194 subjectCert->isLeaf(true);
195 subjectCert->isFromInputCerts(true);
196 outCertGroup.setAllUnused();
197 subjectCert->used(true);
198
199 outErr = outCertGroup.buildCertGroup(
200 *subjectCert,
201 &inCertGroup,
202 DBList,
203 clHand,
204 cspHand,
205 cssmTimeStr,
206 numAnchorCerts,
207 anchorCerts,
208 certsToBeFreed,
209 &certsToBeFreed, // gatheredCerts to accumulate net/DB fetches
210 CSSM_TRUE, // subjectIsInGroup - enables root check on
211 // subject cert
212 actionFlags,
213 policyOid,
214 policyStr,
215 policyStrLen,
216 keyUse,
217
218 verifiedToRoot,
219 verifiedToAnchor,
220 verifiedViaTrustSetting);
221 if(outErr) {
222 CssmError::throwMe(outErr);
223 }
224 }
225
226 /*
227 * Map a policy OID to one of the standard (non-revocation) policies.
228 * Returns true if it's a standard policy.
229 */
230 static bool checkPolicyOid(
231 const CSSM_OID &oid,
232 TPPolicy &tpPolicy) /* RETURNED */
233 {
234 if(tpCompareOids(&oid, &CSSMOID_APPLE_TP_SSL)) {
235 tpPolicy = kTP_SSL;
236 return true;
237 }
238 else if(tpCompareOids(&oid, &CSSMOID_APPLE_X509_BASIC)) {
239 tpPolicy = kTPx509Basic;
240 return true;
241 }
242 else if(tpCompareOids(&oid, &CSSMOID_APPLE_TP_SMIME)) {
243 tpPolicy = kTP_SMIME;
244 return true;
245 }
246 else if(tpCompareOids(&oid, &CSSMOID_APPLE_TP_EAP)) {
247 tpPolicy = kTP_EAP;
248 return true;
249 }
250 else if(tpCompareOids(&oid, &CSSMOID_APPLE_TP_SW_UPDATE_SIGNING)) {
251 /* note: this was CSSMOID_APPLE_TP_CODE_SIGN until 8/15/06 */
252 tpPolicy = kTP_SWUpdateSign;
253 return true;
254 }
255 else if(tpCompareOids(&oid, &CSSMOID_APPLE_TP_RESOURCE_SIGN)) {
256 tpPolicy = kTP_ResourceSign;
257 return true;
258 }
259 else if(tpCompareOids(&oid, &CSSMOID_APPLE_TP_IP_SEC)) {
260 tpPolicy = kTP_IPSec;
261 return true;
262 }
263 else if(tpCompareOids(&oid, &CSSMOID_APPLE_TP_ICHAT)) {
264 tpPolicy = kTP_iChat;
265 return true;
266 }
267 else if(tpCompareOids(&oid, &CSSMOID_APPLE_ISIGN)) {
268 tpPolicy = kTPiSign;
269 return true;
270 }
271 else if(tpCompareOids(&oid, &CSSMOID_APPLE_TP_PKINIT_CLIENT)) {
272 tpPolicy = kTP_PKINIT_Client;
273 return true;
274 }
275 else if(tpCompareOids(&oid, &CSSMOID_APPLE_TP_PKINIT_SERVER)) {
276 tpPolicy = kTP_PKINIT_Server;
277 return true;
278 }
279 else if(tpCompareOids(&oid, &CSSMOID_APPLE_TP_CODE_SIGNING)) {
280 tpPolicy = kTP_CodeSigning;
281 return true;
282 }
283 else if(tpCompareOids(&oid, &CSSMOID_APPLE_TP_PACKAGE_SIGNING)) {
284 tpPolicy = kTP_PackageSigning;
285 return true;
286 }
287 else if(tpCompareOids(&oid, &CSSMOID_APPLE_TP_MACAPPSTORE_RECEIPT)) {
288 tpPolicy = kTP_MacAppStoreRec;
289 return true;
290 }
291 else if(tpCompareOids(&oid, &CSSMOID_APPLE_TP_APPLEID_SHARING)) {
292 tpPolicy = kTP_AppleIDSharing;
293 return true;
294 }
295 else if(tpCompareOids(&oid, &CSSMOID_APPLE_TP_TIMESTAMPING)) {
296 tpPolicy = kTP_TimeStamping;
297 return true;
298 }
299 else if(tpCompareOids(&oid, &CSSMOID_APPLE_TP_PASSBOOK_SIGNING)) {
300 tpPolicy = kTP_PassbookSigning;
301 return true;
302 }
303 else if(tpCompareOids(&oid, &CSSMOID_APPLE_TP_MOBILE_STORE)) {
304 tpPolicy = kTP_MobileStore;
305 return true;
306 }
307 else if(tpCompareOids(&oid, &CSSMOID_APPLE_TP_TEST_MOBILE_STORE)) {
308 tpPolicy = kTP_TestMobileStore;
309 return true;
310 }
311 else if(tpCompareOids(&oid, &CSSMOID_APPLE_TP_ESCROW_SERVICE)) {
312 tpPolicy = kTP_EscrowService;
313 return true;
314 }
315 else if(tpCompareOids(&oid, &CSSMOID_APPLE_TP_PROFILE_SIGNING)) {
316 tpPolicy = kTP_ProfileSigning;
317 return true;
318 }
319 else if(tpCompareOids(&oid, &CSSMOID_APPLE_TP_QA_PROFILE_SIGNING)) {
320 tpPolicy = kTP_QAProfileSigning;
321 return true;
322 }
323 else if(tpCompareOids(&oid, &CSSMOID_APPLE_TP_PCS_ESCROW_SERVICE)) {
324 tpPolicy = kTP_PCSEscrowService;
325 return true;
326 }
327 else if(tpCompareOids(&oid, &CSSMOID_APPLE_TP_PROVISIONING_PROFILE_SIGNING)) {
328 tpPolicy = kTP_ProvisioningProfileSigning;
329 return true;
330 }
331 return false;
332 }
333
334 /*-----------------------------------------------------------------------------
335 * CertGroupVerify
336 *
337 * Description:
338 * -- Construct a cert chain using TP_CertGroupConstruct.
339 * -- Attempt to verify that cert chain against one of the known
340 * good certs passed in AnchorCerts.
341 * -- Optionally enforces additional policies (TBD) when verifying the cert chain.
342 * -- Optionally returns the entire cert chain constructed in
343 * TP_CertGroupConstruct and here, all the way to an anchor cert or as
344 * far as we were able to go, in *Evidence.
345 *
346 * Parameters:
347 * Two handles - to an open CL and CSP. The CSP must be capable of
348 * dealing with the signature algorithms used by the certs. The CL must be
349 * an X.509-savvy CL.
350 *
351 * RawCerts, an unordered array of raw certs in the form of a
352 * CSSM_CERTGROUP_PTR. The first cert of this list is the subject cert
353 * which is eventually to be verified. The other certs can be in any order
354 * and may not even have any relevance to the cert chain being constructed.
355 * They may also be invalid certs.
356 *
357 * DBList, a list of DB/DL handles which may contain certs necessary to
358 * complete the desired cert chain. (Currently not implemented.)
359 *
360 * AnchorCerts, a list of known trusted certs.
361 * NumberOfAnchorCerts, size of AnchorCerts array.
362 *
363 * PolicyIdentifiers, Optional policy OID. NULL indicates default
364 * X.509 trust policy.
365 *
366 * Supported Policies:
367 * CSSMOID_APPLE_ISIGN
368 * CSSMOID_APPLE_X509_BASIC
369 *
370 * For both of these, the associated FieldValue must be {0, NULL},
371 *
372 * NumberOfPolicyIdentifiers, size of PolicyIdentifiers array, must be
373 * zero or one.
374 *
375 * All other arguments must be zero/NULL.
376 *
377 * Returns:
378 * CSSM_OK : cert chain verified all the way back to an AnchorCert.
379 * CSSMERR_TP_INVALID_ANCHOR_CERT : In this case, the cert chain
380 * was validated back to a self-signed (root) cert found in either
381 * CertToBeVerified or in one of the DBs in DBList, but that root cert
382 * was *NOT* found in the AnchorCert list.
383 * CSSMERR_TP_NOT_TRUSTED: no root cert was found and no AnchorCert
384 * verified the end of the constructed cert chain.
385 * CSSMERR_TP_VERIFICATION_FAILURE: a root cert was found which does
386 * not self-verify.
387 * CSSMERR_TP_VERIFY_ACTION_FAILED: indicates a failure of the requested
388 * policy action.
389 * CSSMERR_TP_INVALID_CERTIFICATE: indicates a bad leaf cert.
390 * CSSMERR_TP_INVALID_REQUEST_INPUTS : no incoming VerifyContext.
391 * CSSMERR_TP_CERT_EXPIRED and CSSMERR_TP_CERT_NOT_VALID_YET: see comments
392 * for CertGroupConstruct.
393 * CSSMERR_TP_CERTIFICATE_CANT_OPERATE : issuer cert was found with a partial
394 * public key, rendering full verification impossible.
395 * CSSMERR_TP_INVALID_CERT_AUTHORITY : issuer cert was found with a partial
396 * public key and which failed to perform subsequent signature
397 * verification.
398 *---------------------------------------------------------------------------*/
399
400 void AppleTPSession::CertGroupVerify(CSSM_CL_HANDLE clHand,
401 CSSM_CSP_HANDLE cspHand,
402 const CSSM_CERTGROUP &CertGroupToBeVerified,
403 const CSSM_TP_VERIFY_CONTEXT *VerifyContext,
404 CSSM_TP_VERIFY_CONTEXT_RESULT_PTR VerifyContextResult)
405 {
406 CSSM_BOOL verifiedToRoot = CSSM_FALSE;
407 CSSM_BOOL verifiedToAnchor = CSSM_FALSE;
408 CSSM_BOOL verifiedViaTrustSetting = CSSM_FALSE;
409 CSSM_RETURN constructReturn = CSSM_OK;
410 CSSM_RETURN policyReturn = CSSM_OK;
411 const CSSM_TP_CALLERAUTH_CONTEXT *cred;
412 /* declare volatile as compiler workaround to avoid caching in CR4 */
413 const CSSM_APPLE_TP_ACTION_DATA * volatile actionData = NULL;
414 CSSM_TIMESTRING cssmTimeStr;
415 CSSM_APPLE_TP_ACTION_FLAGS actionFlags = 0;
416 CSSM_TP_STOP_ON tpStopOn = 0;
417
418 /* keep track of whether we did policy checking; if not, we do defaults */
419 bool didCertPolicy = false;
420 bool didRevokePolicy = false;
421
422 /* user trust parameters */
423 CSSM_OID utNullPolicy = {0, NULL};
424 const CSSM_OID *utPolicyOid = NULL;
425 const char *utPolicyStr = NULL;
426 uint32 utPolicyStrLen = 0;
427 SecTrustSettingsKeyUsage utKeyUse = 0;
428 bool utTrustSettingEnabled = false;
429
430 if(VerifyContextResult) {
431 memset(VerifyContextResult, 0, sizeof(*VerifyContextResult));
432 }
433
434 /* verify input args, skipping the ones checked by CertGroupConstruct */
435 if((VerifyContext == NULL) || (VerifyContext->Cred == NULL)) {
436 /* the spec says that this is optional but we require it */
437 CssmError::throwMe(CSSMERR_TP_INVALID_REQUEST_INPUTS);
438 }
439 cred = VerifyContext->Cred;
440
441 /* Optional ActionData affecting all policies */
442 actionData = (CSSM_APPLE_TP_ACTION_DATA * volatile)VerifyContext->ActionData.Data;
443 if(actionData != NULL) {
444 switch(actionData->Version) {
445 case CSSM_APPLE_TP_ACTION_VERSION:
446 if(VerifyContext->ActionData.Length !=
447 sizeof(CSSM_APPLE_TP_ACTION_DATA)) {
448 CssmError::throwMe(CSSMERR_TP_INVALID_ACTION_DATA);
449 }
450 break;
451 /* handle backwards versions here if we ever go beyond version 0 */
452 default:
453 CssmError::throwMe(CSSMERR_TP_INVALID_ACTION_DATA);
454 }
455 actionFlags = actionData->ActionFlags;
456 if(actionFlags & CSSM_TP_ACTION_TRUST_SETTINGS) {
457 utTrustSettingEnabled = true;
458 }
459 }
460
461 /* optional, may be NULL */
462 cssmTimeStr = cred->VerifyTime;
463
464 tpStopOn = cred->VerificationAbortOn;
465 switch(tpStopOn) {
466 /* the only two we support */
467 case CSSM_TP_STOP_ON_NONE:
468 case CSSM_TP_STOP_ON_FIRST_FAIL:
469 break;
470 /* default maps to stop on first fail */
471 case CSSM_TP_STOP_ON_POLICY:
472 tpStopOn = CSSM_TP_STOP_ON_FIRST_FAIL;
473 break;
474 default:
475 CssmError::throwMe(CSSMERR_TP_INVALID_STOP_ON_POLICY);
476 }
477
478 /* now the args we can't deal with */
479 if(cred->CallerCredentials != NULL) {
480 CssmError::throwMe(CSSMERR_TP_INVALID_CALLERAUTH_CONTEXT_POINTER);
481 }
482 /* ...any others? */
483
484 /* set up for optional user trust evaluation */
485 if(utTrustSettingEnabled) {
486 const CSSM_TP_POLICYINFO *pinfo = &cred->Policy;
487 TPPolicy utPolicy = kTPx509Basic;
488
489 /* default policy OID in case caller hasn't specified one */
490 utPolicyOid = &utNullPolicy;
491 if(pinfo->NumberOfPolicyIds == 0) {
492 tpTrustSettingsDbg("CertGroupVerify: User trust enabled but no policies (1)");
493 /* keep going, I guess - no policy-specific info - use kTPx509Basic */
494 }
495 else {
496 CSSM_FIELD_PTR utPolicyField = &pinfo->PolicyIds[0];
497 utPolicyOid = &utPolicyField->FieldOid;
498 bool foundPolicy = checkPolicyOid(*utPolicyOid, utPolicy);
499 if(!foundPolicy) {
500 tpTrustSettingsDbg("CertGroupVerify: User trust enabled but no policies");
501 /* keep going, I guess - no policy-specific info - use kTPx509Basic */
502 }
503 else {
504 /* get policy-specific info */
505 tp_policyTrustSettingParams(utPolicy, &utPolicyField->FieldValue,
506 &utPolicyStr, &utPolicyStrLen, &utKeyUse);
507 }
508 }
509 }
510
511 /* get verified (possibly partial) outCertGroup - error is fatal */
512 /* BUT: we still return partial evidence if asked to...from now on. */
513 TPCertGroup outCertGroup(*this,
514 TGO_Caller); // certs are owned by inCertGroup
515 TPCertGroup inCertGroup(CertGroupToBeVerified, clHand, cspHand, *this,
516 cssmTimeStr, // optional 'this' time
517 true, // firstCertMustBeValid
518 TGO_Group);
519
520 /* set up for disposal of TPCertInfos created by CertGroupConstructPriv */
521 TPCertGroup gatheredCerts(*this, TGO_Group);
522
523 try {
524 CertGroupConstructPriv(
525 clHand,
526 cspHand,
527 inCertGroup,
528 cred->DBList,
529 cssmTimeStr,
530 cred->NumberOfAnchorCerts,
531 cred->AnchorCerts,
532 actionFlags,
533 utPolicyOid,
534 utPolicyStr,
535 utPolicyStrLen,
536 utKeyUse,
537 gatheredCerts,
538 verifiedToRoot,
539 verifiedToAnchor,
540 verifiedViaTrustSetting,
541 outCertGroup);
542 }
543 catch(const CssmError &cerr) {
544 constructReturn = cerr.error;
545 /* abort if no certs found */
546 if(outCertGroup.numCerts() == 0) {
547 CssmError::throwMe(constructReturn);
548 }
549 /* else press on, collecting as much info as we can */
550 }
551 /* others are way fatal */
552 assert(outCertGroup.numCerts() >= 1);
553
554 /* Infer interim status from return values */
555 switch(constructReturn) {
556 /* these values do not get overridden */
557 case CSSMERR_TP_CERTIFICATE_CANT_OPERATE:
558 case CSSMERR_TP_INVALID_CERT_AUTHORITY:
559 case CSSMERR_APPLETP_TRUST_SETTING_DENY:
560 case errSecInvalidTrustSettings:
561 break;
562 default:
563 /* infer status from these values... */
564 if(verifiedToAnchor || verifiedViaTrustSetting) {
565 /* full success; anchor doesn't have to be root */
566 constructReturn = CSSM_OK;
567 }
568 else if(verifiedToRoot) {
569 if(actionFlags & CSSM_TP_ACTION_IMPLICIT_ANCHORS) {
570 constructReturn = CSSM_OK;
571 }
572 else {
573 /* verified to root which is not an anchor */
574 constructReturn = CSSMERR_TP_INVALID_ANCHOR_CERT;
575 }
576 }
577 else {
578 /* partial chain, no root, not verifiable by anchor */
579 constructReturn = CSSMERR_TP_NOT_TRUSTED;
580 }
581
582 /*
583 * Those errors can be allowed, cert-chain-wide, per individual
584 * certs' allowedErrors
585 */
586 if((constructReturn != CSSM_OK) &&
587 outCertGroup.isAllowedError(constructReturn)) {
588 constructReturn = CSSM_OK;
589 }
590
591 break;
592 }
593
594 /*
595 * Parameters passed to tp_policyVerify() and which vary per policy
596 * in the loop below
597 */
598 TPPolicy tpPolicy;
599 const CSSM_APPLE_TP_SSL_OPTIONS *sslOpts;
600 CSSM_RETURN thisPolicyRtn = CSSM_OK; // returned from tp_policyVerify()
601
602 /* common CRL verify parameters */
603 TPCrlGroup *crlGroup = NULL;
604 try {
605 crlGroup = new TPCrlGroup(&VerifyContext->Crls,
606 clHand, cspHand,
607 *this, // alloc
608 NULL, // cssmTimeStr - we want CRLs that are valid 'now'
609 TGO_Group);
610 }
611 catch(const CssmError &cerr) {
612 CSSM_RETURN cr = cerr.error;
613 /* I don't see a straightforward way to report this error,
614 * other than adding it to the leaf cert's status... */
615 outCertGroup.certAtIndex(0)->addStatusCode(cr);
616 tpDebug("CertGroupVerify: error constructing CrlGroup; continuing\n");
617 }
618 /* others are way fatal */
619
620 TPVerifyContext revokeVfyContext(*this,
621 clHand,
622 cspHand,
623 cssmTimeStr,
624 cred->NumberOfAnchorCerts,
625 cred->AnchorCerts,
626 &inCertGroup,
627 crlGroup,
628 /*
629 * This may consist of certs gathered from the net (which is the purpose
630 * of this argument) and from DLDBs (a side-effect optimization).
631 */
632 gatheredCerts,
633 cred->DBList,
634 kRevokeNone, // policy
635 actionFlags,
636 NULL, // CRL options
637 NULL, // OCSP options
638 utPolicyOid,
639 utPolicyStr,
640 utPolicyStrLen,
641 utKeyUse);
642
643 /* true if we're to execute tp_policyVerify at end of loop */
644 bool doPolicyVerify;
645 /* true if we're to execute a revocation policy at end of loop */
646 bool doRevocationPolicy;
647
648 /* grind thru each policy */
649 for(uint32 polDex=0; polDex<cred->Policy.NumberOfPolicyIds; polDex++) {
650 if(cred->Policy.PolicyIds == NULL) {
651 policyReturn = CSSMERR_TP_INVALID_POLICY_IDENTIFIERS;
652 break;
653 }
654 CSSM_FIELD_PTR policyId = &cred->Policy.PolicyIds[polDex];
655 const CSSM_DATA *fieldVal = &policyId->FieldValue;
656 const CSSM_OID *oid = &policyId->FieldOid;
657 thisPolicyRtn = CSSM_OK;
658 doPolicyVerify = false;
659 doRevocationPolicy = false;
660 sslOpts = NULL;
661
662 /* first the basic cert policies */
663 doPolicyVerify = checkPolicyOid(*oid, tpPolicy);
664 if(doPolicyVerify) {
665 /* some basic checks... */
666 bool policyAbort = false;
667 switch(tpPolicy) {
668 case kTPx509Basic:
669 case kTPiSign:
670 case kTP_PKINIT_Client:
671 case kTP_PKINIT_Server:
672 if(fieldVal->Data != NULL) {
673 policyReturn = CSSMERR_TP_INVALID_POLICY_IDENTIFIERS;
674 policyAbort = true;
675 break;
676 }
677 break;
678 default:
679 break;
680 }
681 if(policyAbort) {
682 break;
683 }
684 }
685
686 /*
687 * Now revocation policies. Note some fields in revokeVfyContext can
688 * accumulate across multiple policy calls, e.g., signerCerts.
689 */
690 else if(tpCompareOids(oid, &CSSMOID_APPLE_TP_REVOCATION_CRL)) {
691 /* CRL-specific options */
692 const CSSM_APPLE_TP_CRL_OPTIONS *crlOpts;
693 crlOpts = (CSSM_APPLE_TP_CRL_OPTIONS *)fieldVal->Data;
694 thisPolicyRtn = CSSM_OK;
695 if(crlOpts != NULL) {
696 switch(crlOpts->Version) {
697 case CSSM_APPLE_TP_CRL_OPTS_VERSION:
698 if(fieldVal->Length !=
699 sizeof(CSSM_APPLE_TP_CRL_OPTIONS)) {
700 thisPolicyRtn =
701 CSSMERR_TP_INVALID_POLICY_IDENTIFIERS;
702 break;
703 }
704 break;
705 /* handle backwards compatibility here if necessary */
706 default:
707 thisPolicyRtn = CSSMERR_TP_INVALID_POLICY_IDENTIFIERS;
708 break;
709 }
710 if(thisPolicyRtn != CSSM_OK) {
711 policyReturn = thisPolicyRtn;
712 break;
713 }
714 }
715 revokeVfyContext.policy = kRevokeCrlBasic;
716 revokeVfyContext.crlOpts = crlOpts;
717 doRevocationPolicy = true;
718 }
719 else if(tpCompareOids(oid, &CSSMOID_APPLE_TP_REVOCATION_OCSP)) {
720 /* OCSP-specific options */
721 const CSSM_APPLE_TP_OCSP_OPTIONS *ocspOpts;
722 ocspOpts = (CSSM_APPLE_TP_OCSP_OPTIONS *)fieldVal->Data;
723 thisPolicyRtn = CSSM_OK;
724 if(ocspOpts != NULL) {
725 switch(ocspOpts->Version) {
726 case CSSM_APPLE_TP_OCSP_OPTS_VERSION:
727 if(fieldVal->Length !=
728 sizeof(CSSM_APPLE_TP_OCSP_OPTIONS)) {
729 thisPolicyRtn =
730 CSSMERR_TP_INVALID_POLICY_IDENTIFIERS;
731 break;
732 }
733 break;
734 /* handle backwards compatibility here if necessary */
735 default:
736 thisPolicyRtn = CSSMERR_TP_INVALID_POLICY_IDENTIFIERS;
737 break;
738 }
739 if(thisPolicyRtn != CSSM_OK) {
740 policyReturn = thisPolicyRtn;
741 break;
742 }
743 }
744 revokeVfyContext.policy = kRevokeOcsp;
745 revokeVfyContext.ocspOpts = ocspOpts;
746 doRevocationPolicy = true;
747 }
748 /* etc. - add more policies here */
749 else {
750 /* unknown TP policy OID */
751 policyReturn = CSSMERR_TP_INVALID_POLICY_IDENTIFIERS;
752 break;
753 }
754
755 /* common cert policy call */
756 if(doPolicyVerify) {
757 assert(!doRevocationPolicy); // one at a time
758 thisPolicyRtn = tp_policyVerify(tpPolicy,
759 *this,
760 clHand,
761 cspHand,
762 &outCertGroup,
763 verifiedToRoot,
764 verifiedViaTrustSetting,
765 actionFlags,
766 fieldVal,
767 cred->Policy.PolicyControl); // not currently used
768 didCertPolicy = true;
769 }
770 /* common revocation policy call */
771 if(doRevocationPolicy) {
772 assert(!doPolicyVerify); // one at a time
773 thisPolicyRtn = tpRevocationPolicyVerify(revokeVfyContext, outCertGroup);
774 didRevokePolicy = true;
775 }
776 /* See if possible error is allowed, cert-chain-wide. */
777 if((thisPolicyRtn != CSSM_OK) &&
778 outCertGroup.isAllowedError(thisPolicyRtn)) {
779 thisPolicyRtn = CSSM_OK;
780 }
781 if(thisPolicyRtn) {
782 /* Now remember the error if it's the first policy
783 * error we've seen. */
784 if(policyReturn == CSSM_OK) {
785 policyReturn = thisPolicyRtn;
786 }
787 /* Keep going? */
788 if(tpStopOn == CSSM_TP_STOP_ON_FIRST_FAIL) {
789 /* Nope; we're done with policy evaluation */
790 break;
791 }
792 }
793 } /* for each policy */
794
795 /*
796 * Upon completion of the above loop, perform default policy ops if
797 * appropriate.
798 */
799 if((policyReturn == CSSM_OK) || (tpStopOn == CSSM_TP_STOP_ON_NONE)) {
800 if(!didCertPolicy) {
801 policyReturn = tp_policyVerify(kTPDefault,
802 *this,
803 clHand,
804 cspHand,
805 &outCertGroup,
806 verifiedToRoot,
807 verifiedViaTrustSetting,
808 actionFlags,
809 NULL, // policyFieldData
810 cred->Policy.PolicyControl); // not currently used
811 /* See if error is allowed, cert-chain-wide. */
812 if((policyReturn != CSSM_OK) &&
813 outCertGroup.isAllowedError(policyReturn)) {
814 policyReturn = CSSM_OK;
815 }
816 }
817 if( !didRevokePolicy && // no revoke policy yet
818 ( (policyReturn == CSSM_OK || // default cert policy OK
819 (tpStopOn == CSSM_TP_STOP_ON_NONE)) // keep going anyway
820 )
821 ) {
822 revokeVfyContext.policy = TP_CRL_POLICY_DEFAULT;
823 CSSM_RETURN thisPolicyRtn = tpRevocationPolicyVerify(revokeVfyContext,
824 outCertGroup);
825 if((thisPolicyRtn != CSSM_OK) &&
826 outCertGroup.isAllowedError(thisPolicyRtn)) {
827 thisPolicyRtn = CSSM_OK;
828 }
829 if((thisPolicyRtn != CSSM_OK) && (policyReturn == CSSM_OK)) {
830 policyReturn = thisPolicyRtn;
831 }
832
833 }
834 } /* default policy opts */
835
836 delete crlGroup;
837
838 /* return evidence - i.e., constructed chain - if asked to */
839 if(VerifyContextResult != NULL) {
840 /*
841 * VerifyContextResult->Evidence[0] : CSSM_TP_APPLE_EVIDENCE_HEADER
842 * VerifyContextResult->Evidence[1] : CSSM_CERTGROUP
843 * VerifyContextResult->Evidence[2] : CSSM_TP_APPLE_EVIDENCE_INFO
844 */
845 VerifyContextResult->NumberOfEvidences = 3;
846 VerifyContextResult->Evidence =
847 (CSSM_EVIDENCE_PTR)calloc(3, sizeof(CSSM_EVIDENCE));
848
849 CSSM_TP_APPLE_EVIDENCE_HEADER *hdr =
850 (CSSM_TP_APPLE_EVIDENCE_HEADER *)malloc(
851 sizeof(CSSM_TP_APPLE_EVIDENCE_HEADER));
852 hdr->Version = CSSM_TP_APPLE_EVIDENCE_VERSION;
853 CSSM_EVIDENCE_PTR ev = &VerifyContextResult->Evidence[0];
854 ev->EvidenceForm = CSSM_EVIDENCE_FORM_APPLE_HEADER;
855 ev->Evidence = hdr;
856
857 ev = &VerifyContextResult->Evidence[1];
858 ev->EvidenceForm = CSSM_EVIDENCE_FORM_APPLE_CERTGROUP;
859 ev->Evidence = outCertGroup.buildCssmCertGroup();
860
861 ev = &VerifyContextResult->Evidence[2];
862 ev->EvidenceForm = CSSM_EVIDENCE_FORM_APPLE_CERT_INFO;
863 ev->Evidence = outCertGroup.buildCssmEvidenceInfo();
864 }
865 else {
866 /* caller responsible for freeing these if they are for evidence.... */
867 outCertGroup.freeDbRecords();
868 }
869 CSSM_RETURN outErr = outCertGroup.getReturnCode(constructReturn, policyReturn,
870 actionFlags);
871
872 if(outErr) {
873 CssmError::throwMe(outErr);
874 }
875 }
876
877