]> git.saurik.com Git - apple/security.git/blob - OSX/libsecurity_apple_x509_tp/lib/tpCertGroup.cpp
Security-57337.20.44.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 "tpCertAllowList.h"
28 #include "tpPolicies.h"
29 #include "tpdebugging.h"
30 #include "tpCrlVerify.h"
31 #include <Security/oidsalg.h>
32 #include <Security/cssmapple.h>
33
34 /*
35 * This is a temporary hack to allow verification of PKINIT server certs
36 * which are self-signed and not in the system anchors list. If the self-
37 * signed cert is in a magic keychain (whose location is not published),
38 * we'll allow it as if it were indeed a full-fledged anchor cert.
39 */
40 #define TP_PKINIT_SERVER_HACK 1
41 #if TP_PKINIT_SERVER_HACK
42
43 #include <Security/SecKeychain.h>
44 #include <Security/SecKeychainSearch.h>
45 #include <Security/SecCertificate.h>
46 #include <Security/oidscert.h>
47 #include <sys/types.h>
48 #include <pwd.h>
49
50 #define CFRELEASE(cf) if(cf) { CFRelease(cf); }
51
52 /*
53 * Returns true if we are to allow/trust the specified
54 * cert as a PKINIT-only anchor.
55 */
56 static bool tpCheckPkinitServerCert(
57 TPCertGroup &certGroup)
58 {
59 /*
60 * Basic requirement: exactly one cert, self-signed.
61 * The numCerts == 1 requirement might change...
62 */
63 unsigned numCerts = certGroup.numCerts();
64 if(numCerts != 1) {
65 tpDebug("tpCheckPkinitServerCert: too many certs");
66 return false;
67 }
68 /* end of chain... */
69 TPCertInfo *theCert = certGroup.certAtIndex(numCerts - 1);
70 if(!theCert->isSelfSigned()) {
71 tpDebug("tpCheckPkinitServerCert: 1 cert, not self-signed");
72 return false;
73 }
74 const CSSM_DATA *subjectName = theCert->subjectName();
75
76 /*
77 * Open the magic keychain.
78 * We're going up and over the Sec layer here, not generally
79 * kosher, but this is a hack.
80 */
81 OSStatus ortn;
82 SecKeychainRef kcRef = NULL;
83 string fullPathName;
84 const char *homeDir = getenv("HOME");
85 if (homeDir == NULL)
86 {
87 // If $HOME is unset get the current user's home directory
88 // from the passwd file.
89 uid_t uid = geteuid();
90 if (!uid) uid = getuid();
91 struct passwd *pw = getpwuid(uid);
92 if (!pw) {
93 return false;
94 }
95 homeDir = pw->pw_dir;
96 }
97 fullPathName = homeDir;
98 fullPathName += "/Library/Application Support/PKINIT/TrustedServers.keychain";
99 ortn = SecKeychainOpen(fullPathName.c_str(), &kcRef);
100 if(ortn) {
101 tpDebug("tpCheckPkinitServerCert: keychain not found (1)");
102 return false;
103 }
104 /* subsequent errors to errOut: */
105
106 bool ourRtn = false;
107 SecKeychainStatus kcStatus;
108 CSSM_DATA_PTR subjSerial = NULL;
109 CSSM_RETURN crtn;
110 SecKeychainSearchRef srchRef = NULL;
111 SecKeychainAttributeList attrList;
112 SecKeychainAttribute attrs[2];
113 SecKeychainItemRef foundItem = NULL;
114
115 ortn = SecKeychainGetStatus(kcRef, &kcStatus);
116 if(ortn) {
117 tpDebug("tpCheckPkinitServerCert: keychain not found (2)");
118 goto errOut;
119 }
120
121 /*
122 * We already have this cert's normalized name; get its
123 * serial number.
124 */
125 crtn = theCert->fetchField(&CSSMOID_X509V1SerialNumber, &subjSerial);
126 if(crtn) {
127 /* should never happen */
128 tpDebug("tpCheckPkinitServerCert: error fetching serial number");
129 goto errOut;
130 }
131
132 attrs[0].tag = kSecSubjectItemAttr;
133 attrs[0].length = (UInt32)subjectName->Length;
134 attrs[0].data = subjectName->Data;
135 attrs[1].tag = kSecSerialNumberItemAttr;
136 attrs[1].length = (UInt32)subjSerial->Length;
137 attrs[1].data = subjSerial->Data;
138 attrList.count = 2;
139 attrList.attr = attrs;
140
141 ortn = SecKeychainSearchCreateFromAttributes(kcRef,
142 kSecCertificateItemClass,
143 &attrList,
144 &srchRef);
145 if(ortn) {
146 tpDebug("tpCheckPkinitServerCert: search failure");
147 goto errOut;
148 }
149 for(;;) {
150 ortn = SecKeychainSearchCopyNext(srchRef, &foundItem);
151 if(ortn) {
152 tpDebug("tpCheckPkinitServerCert: end search");
153 break;
154 }
155
156 /* found a matching cert; do byte-for-byte compare */
157 CSSM_DATA certData;
158 ortn = SecCertificateGetData((SecCertificateRef)foundItem, &certData);
159 if(ortn) {
160 tpDebug("tpCheckPkinitServerCert: SecCertificateGetData failure");
161 continue;
162 }
163 if(tpCompareCssmData(&certData, theCert->itemData())){
164 tpDebug("tpCheckPkinitServerCert: FOUND CERT");
165 ourRtn = true;
166 break;
167 }
168 tpDebug("tpCheckPkinitServerCert: skipping matching cert");
169 CFRelease(foundItem);
170 foundItem = NULL;
171 }
172 errOut:
173 CFRELEASE(kcRef);
174 CFRELEASE(srchRef);
175 CFRELEASE(foundItem);
176 if(subjSerial != NULL) {
177 theCert->freeField(&CSSMOID_X509V1SerialNumber, subjSerial);
178 }
179 return ourRtn;
180 }
181 #endif /* TP_PKINIT_SERVER_HACK */
182
183 /*-----------------------------------------------------------------------------
184 * CertGroupConstruct
185 *
186 * Description:
187 * This function returns a pointer to a mallocd CSSM_CERTGROUP which
188 * refers to a mallocd list of raw ordered X.509 certs which verify back as
189 * far as the TP is able to go. The first cert of the returned list is the
190 * subject cert. The TP will attempt to search thru the DBs passed in
191 * DBList in order to complete the chain. The chain is completed when a
192 * self-signed (root) cert is found in the chain. The root cert may be
193 * present in the input CertGroupFrag, or it may have been obtained from
194 * one of the DBs passed in DBList. It is not an error if no root cert is
195 * found.
196 *
197 * The error conditions are:
198 * -- The first cert of CertGroupFrag is an invalid cert. NULL is returned,
199 * err = CSSM_TP_INVALID_CERTIFICATE.
200 * -- The root cert (if found) fails to verify. Valid certgroup is returned,
201 * err = CSSMERR_TP_VERIFICATION_FAILURE.
202 * -- Any cert in the (possibly partially) constructed chain has expired or
203 * isn't valid yet, err = CSSMERR_TP_CERT_EXPIRED or
204 * CSSMERR_TP_CERT_NOT_VALID_YET. A CertGroup is returned.
205 * -- CSSMERR_TP_CERT_EXPIRED and CSSMERR_TP_CERT_NOT_VALID_YET. If one of these
206 * conditions obtains for the first (leaf) cert, the function throws this
207 * error immediately and the outgoing cert group is empty. For subsequent certs,
208 * the temporal validity of a cert is only tested AFTER a cert successfully
209 * meets the cert chaining criteria (subject/issuer match and signature
210 * verify). A cert in a chain with this error is not added to the outgoing
211 * cert group.
212 * -- the usual errors like bad handle or memory failure.
213 *
214 * Parameters:
215 * Two handles - to an open CL and CSP. The CSP must be capable of
216 * dealing with the signature algorithms used by the certs. The CL must be
217 * an X.509-savvy CL.
218 *
219 * CertGroupFrag, an unordered array of raw X.509 certs in the form of a
220 * CSSM_CERTGROUP_PTR. The first cert of this list is the subject cert
221 * which is eventually to be verified. The other certs can be in any order
222 * and may not even have any relevance to the cert chain being constructed.
223 * They may also be invalid certs.
224 *
225 * DBList, a list of DB/DL handles which may contain certs necessary to
226 * complete the desired cert chain. (Not currently implemented.)
227 *
228 *---------------------------------------------------------------------------*/
229
230 /* public version */
231 void AppleTPSession::CertGroupConstruct(CSSM_CL_HANDLE clHand,
232 CSSM_CSP_HANDLE cspHand,
233 const CSSM_DL_DB_LIST &DBList,
234 const void *ConstructParams,
235 const CSSM_CERTGROUP &CertGroupFrag,
236 CSSM_CERTGROUP_PTR &CertGroup)
237 {
238 TPCertGroup outCertGroup(*this, TGO_Caller);
239 TPCertGroup inCertGroup(CertGroupFrag,
240 clHand,
241 cspHand,
242 *this,
243 NULL, // cssmTimeStr
244 true, // firstCertMustBeValid
245 TGO_Group);
246
247 /* set up for disposal of TPCertInfos created by CertGroupConstructPriv */
248 TPCertGroup gatheredCerts(*this, TGO_Group);
249
250 CSSM_RETURN constructReturn = CSSM_OK;
251 CSSM_APPLE_TP_ACTION_FLAGS actionFlags = 0;
252 CSSM_BOOL verifiedToRoot; // not used
253 CSSM_BOOL verifiedToAnchor; // not used
254 CSSM_BOOL verifiedViaTrustSetting; // not used
255
256 try {
257 CertGroupConstructPriv(clHand,
258 cspHand,
259 inCertGroup,
260 &DBList,
261 NULL, // cssmTimeStr
262 /* no anchors */
263 0, NULL,
264 actionFlags,
265 /* no user trust */
266 NULL, NULL, 0, 0,
267 gatheredCerts,
268 verifiedToRoot,
269 verifiedToAnchor,
270 verifiedViaTrustSetting,
271 outCertGroup);
272 }
273 catch(const CssmError &cerr) {
274 constructReturn = cerr.error;
275 /* abort if no certs found */
276 if(outCertGroup.numCerts() == 0) {
277 CssmError::throwMe(constructReturn);
278 }
279 }
280 CertGroup = outCertGroup.buildCssmCertGroup();
281 /* caller of this function never gets evidence... */
282 outCertGroup.freeDbRecords();
283
284 if(constructReturn) {
285 CssmError::throwMe(constructReturn);
286 }
287 }
288
289
290 /*
291 * Private version of CertGroupConstruct, used by CertGroupConstruct and
292 * CertGroupVerify. Populates a TP-style TPCertGroup for further processing.
293 * This only throws CSSM-style exceptions in the following cases:
294 *
295 * -- input parameter errors
296 * -- the first (leaf) cert is bad (doesn't parse, expired, not valid yet).
297 * -- root found but it doesn't self-verify
298 *
299 * All other cert-related errors simply result in the bad cert being ignored.
300 * Other exceptions are gross system errors like malloc failure.
301 */
302 void AppleTPSession::CertGroupConstructPriv(CSSM_CL_HANDLE clHand,
303 CSSM_CSP_HANDLE cspHand,
304 TPCertGroup &inCertGroup,
305 const CSSM_DL_DB_LIST *DBList, // optional here
306 const char *cssmTimeStr, // optional
307
308 /* trusted anchors, optional */
309 /* FIXME - maybe this should be a TPCertGroup */
310 uint32 numAnchorCerts,
311 const CSSM_DATA *anchorCerts,
312
313 /* CSSM_TP_ACTION_FETCH_CERT_FROM_NET, CSSM_TP_ACTION_TRUST_SETTINGS */
314 CSSM_APPLE_TP_ACTION_FLAGS actionFlags,
315
316 /* optional user trust parameters */
317 const CSSM_OID *policyOid,
318 const char *policyStr,
319 uint32 policyStrLen,
320 SecTrustSettingsKeyUsage keyUse,
321
322 /*
323 * Certs to be freed by caller (i.e., TPCertInfo which we allocate
324 * as a result of using a cert from anchorCerts or dbList) are added
325 * to this group.
326 */
327 TPCertGroup &certsToBeFreed,
328
329 /* returned */
330 CSSM_BOOL &verifiedToRoot, // end of chain self-verifies
331 CSSM_BOOL &verifiedToAnchor, // end of chain in anchors
332 CSSM_BOOL &verifiedViaTrustSetting, // chain ends per User Trust setting
333 TPCertGroup &outCertGroup) // RETURNED
334 {
335 TPCertInfo *subjectCert; // the one we're working on
336 CSSM_RETURN outErr = CSSM_OK;
337
338 /* this'll be the first subject cert in the main loop */
339 subjectCert = inCertGroup.certAtIndex(0);
340
341 /* Append leaf cert to outCertGroup */
342 outCertGroup.appendCert(subjectCert);
343 subjectCert->isLeaf(true);
344 subjectCert->isFromInputCerts(true);
345 outCertGroup.setAllUnused();
346 subjectCert->used(true);
347
348 outErr = outCertGroup.buildCertGroup(
349 *subjectCert,
350 &inCertGroup,
351 DBList,
352 clHand,
353 cspHand,
354 cssmTimeStr,
355 numAnchorCerts,
356 anchorCerts,
357 certsToBeFreed,
358 &certsToBeFreed, // gatheredCerts to accumulate net/DB fetches
359 CSSM_TRUE, // subjectIsInGroup - enables root check on
360 // subject cert
361 actionFlags,
362 policyOid,
363 policyStr,
364 policyStrLen,
365 keyUse,
366
367 verifiedToRoot,
368 verifiedToAnchor,
369 verifiedViaTrustSetting);
370 if(outErr) {
371 CssmError::throwMe(outErr);
372 }
373 }
374
375 /*
376 * Map a policy OID to one of the standard (non-revocation) policies.
377 * Returns true if it's a standard policy.
378 */
379 static bool checkPolicyOid(
380 const CSSM_OID &oid,
381 TPPolicy &tpPolicy) /* RETURNED */
382 {
383 if(tpCompareOids(&oid, &CSSMOID_APPLE_TP_SSL)) {
384 tpPolicy = kTP_SSL;
385 return true;
386 }
387 else if(tpCompareOids(&oid, &CSSMOID_APPLE_X509_BASIC)) {
388 tpPolicy = kTPx509Basic;
389 return true;
390 }
391 else if(tpCompareOids(&oid, &CSSMOID_APPLE_TP_SMIME)) {
392 tpPolicy = kTP_SMIME;
393 return true;
394 }
395 else if(tpCompareOids(&oid, &CSSMOID_APPLE_TP_EAP)) {
396 tpPolicy = kTP_EAP;
397 return true;
398 }
399 else if(tpCompareOids(&oid, &CSSMOID_APPLE_TP_SW_UPDATE_SIGNING)) {
400 /* note: this was CSSMOID_APPLE_TP_CODE_SIGN until 8/15/06 */
401 tpPolicy = kTP_SWUpdateSign;
402 return true;
403 }
404 else if(tpCompareOids(&oid, &CSSMOID_APPLE_TP_RESOURCE_SIGN)) {
405 tpPolicy = kTP_ResourceSign;
406 return true;
407 }
408 else if(tpCompareOids(&oid, &CSSMOID_APPLE_TP_IP_SEC)) {
409 tpPolicy = kTP_IPSec;
410 return true;
411 }
412 else if(tpCompareOids(&oid, &CSSMOID_APPLE_TP_ICHAT)) {
413 tpPolicy = kTP_iChat;
414 return true;
415 }
416 else if(tpCompareOids(&oid, &CSSMOID_APPLE_ISIGN)) {
417 tpPolicy = kTPiSign;
418 return true;
419 }
420 else if(tpCompareOids(&oid, &CSSMOID_APPLE_TP_PKINIT_CLIENT)) {
421 tpPolicy = kTP_PKINIT_Client;
422 return true;
423 }
424 else if(tpCompareOids(&oid, &CSSMOID_APPLE_TP_PKINIT_SERVER)) {
425 tpPolicy = kTP_PKINIT_Server;
426 return true;
427 }
428 else if(tpCompareOids(&oid, &CSSMOID_APPLE_TP_CODE_SIGNING)) {
429 tpPolicy = kTP_CodeSigning;
430 return true;
431 }
432 else if(tpCompareOids(&oid, &CSSMOID_APPLE_TP_PACKAGE_SIGNING)) {
433 tpPolicy = kTP_PackageSigning;
434 return true;
435 }
436 else if(tpCompareOids(&oid, &CSSMOID_APPLE_TP_MACAPPSTORE_RECEIPT)) {
437 tpPolicy = kTP_MacAppStoreRec;
438 return true;
439 }
440 else if(tpCompareOids(&oid, &CSSMOID_APPLE_TP_APPLEID_SHARING)) {
441 tpPolicy = kTP_AppleIDSharing;
442 return true;
443 }
444 else if(tpCompareOids(&oid, &CSSMOID_APPLE_TP_TIMESTAMPING)) {
445 tpPolicy = kTP_TimeStamping;
446 return true;
447 }
448 else if(tpCompareOids(&oid, &CSSMOID_APPLE_TP_PASSBOOK_SIGNING)) {
449 tpPolicy = kTP_PassbookSigning;
450 return true;
451 }
452 else if(tpCompareOids(&oid, &CSSMOID_APPLE_TP_MOBILE_STORE)) {
453 tpPolicy = kTP_MobileStore;
454 return true;
455 }
456 else if(tpCompareOids(&oid, &CSSMOID_APPLE_TP_TEST_MOBILE_STORE)) {
457 tpPolicy = kTP_TestMobileStore;
458 return true;
459 }
460 else if(tpCompareOids(&oid, &CSSMOID_APPLE_TP_ESCROW_SERVICE)) {
461 tpPolicy = kTP_EscrowService;
462 return true;
463 }
464 else if(tpCompareOids(&oid, &CSSMOID_APPLE_TP_PROFILE_SIGNING)) {
465 tpPolicy = kTP_ProfileSigning;
466 return true;
467 }
468 else if(tpCompareOids(&oid, &CSSMOID_APPLE_TP_QA_PROFILE_SIGNING)) {
469 tpPolicy = kTP_QAProfileSigning;
470 return true;
471 }
472 else if(tpCompareOids(&oid, &CSSMOID_APPLE_TP_PCS_ESCROW_SERVICE)) {
473 tpPolicy = kTP_PCSEscrowService;
474 return true;
475 }
476 else if(tpCompareOids(&oid, &CSSMOID_APPLE_TP_PROVISIONING_PROFILE_SIGNING)) {
477 tpPolicy = kTP_ProvisioningProfileSigning;
478 return true;
479 }
480 return false;
481 }
482
483 /*-----------------------------------------------------------------------------
484 * CertGroupVerify
485 *
486 * Description:
487 * -- Construct a cert chain using TP_CertGroupConstruct.
488 * -- Attempt to verify that cert chain against one of the known
489 * good certs passed in AnchorCerts.
490 * -- Optionally enforces additional policies (TBD) when verifying the cert chain.
491 * -- Optionally returns the entire cert chain constructed in
492 * TP_CertGroupConstruct and here, all the way to an anchor cert or as
493 * far as we were able to go, in *Evidence.
494 *
495 * Parameters:
496 * Two handles - to an open CL and CSP. The CSP must be capable of
497 * dealing with the signature algorithms used by the certs. The CL must be
498 * an X.509-savvy CL.
499 *
500 * RawCerts, an unordered array of raw certs in the form of a
501 * CSSM_CERTGROUP_PTR. The first cert of this list is the subject cert
502 * which is eventually to be verified. The other certs can be in any order
503 * and may not even have any relevance to the cert chain being constructed.
504 * They may also be invalid certs.
505 *
506 * DBList, a list of DB/DL handles which may contain certs necessary to
507 * complete the desired cert chain. (Currently not implemented.)
508 *
509 * AnchorCerts, a list of known trusted certs.
510 * NumberOfAnchorCerts, size of AnchorCerts array.
511 *
512 * PolicyIdentifiers, Optional policy OID. NULL indicates default
513 * X.509 trust policy.
514 *
515 * Supported Policies:
516 * CSSMOID_APPLE_ISIGN
517 * CSSMOID_APPLE_X509_BASIC
518 *
519 * For both of these, the associated FieldValue must be {0, NULL},
520 *
521 * NumberOfPolicyIdentifiers, size of PolicyIdentifiers array, must be
522 * zero or one.
523 *
524 * All other arguments must be zero/NULL.
525 *
526 * Returns:
527 * CSSM_OK : cert chain verified all the way back to an AnchorCert.
528 * CSSMERR_TP_INVALID_ANCHOR_CERT : In this case, the cert chain
529 * was validated back to a self-signed (root) cert found in either
530 * CertToBeVerified or in one of the DBs in DBList, but that root cert
531 * was *NOT* found in the AnchorCert list.
532 * CSSMERR_TP_NOT_TRUSTED: no root cert was found and no AnchorCert
533 * verified the end of the constructed cert chain.
534 * CSSMERR_TP_VERIFICATION_FAILURE: a root cert was found which does
535 * not self-verify.
536 * CSSMERR_TP_VERIFY_ACTION_FAILED: indicates a failure of the requested
537 * policy action.
538 * CSSMERR_TP_INVALID_CERTIFICATE: indicates a bad leaf cert.
539 * CSSMERR_TP_INVALID_REQUEST_INPUTS : no incoming VerifyContext.
540 * CSSMERR_TP_CERT_EXPIRED and CSSMERR_TP_CERT_NOT_VALID_YET: see comments
541 * for CertGroupConstruct.
542 * CSSMERR_TP_CERTIFICATE_CANT_OPERATE : issuer cert was found with a partial
543 * public key, rendering full verification impossible.
544 * CSSMERR_TP_INVALID_CERT_AUTHORITY : issuer cert was found with a partial
545 * public key and which failed to perform subsequent signature
546 * verification.
547 *---------------------------------------------------------------------------*/
548
549 void AppleTPSession::CertGroupVerify(CSSM_CL_HANDLE clHand,
550 CSSM_CSP_HANDLE cspHand,
551 const CSSM_CERTGROUP &CertGroupToBeVerified,
552 const CSSM_TP_VERIFY_CONTEXT *VerifyContext,
553 CSSM_TP_VERIFY_CONTEXT_RESULT_PTR VerifyContextResult)
554 {
555 CSSM_BOOL verifiedToRoot = CSSM_FALSE;
556 CSSM_BOOL verifiedToAnchor = CSSM_FALSE;
557 CSSM_BOOL verifiedViaTrustSetting = CSSM_FALSE;
558 CSSM_RETURN constructReturn = CSSM_OK;
559 CSSM_RETURN policyReturn = CSSM_OK;
560 const CSSM_TP_CALLERAUTH_CONTEXT *cred;
561 /* declare volatile as compiler workaround to avoid caching in CR4 */
562 const CSSM_APPLE_TP_ACTION_DATA * volatile actionData = NULL;
563 CSSM_TIMESTRING cssmTimeStr;
564 CSSM_APPLE_TP_ACTION_FLAGS actionFlags = 0;
565 CSSM_TP_STOP_ON tpStopOn = 0;
566
567 /* keep track of whether we did policy checking; if not, we do defaults */
568 bool didCertPolicy = false;
569 bool didRevokePolicy = false;
570
571 /* user trust parameters */
572 CSSM_OID utNullPolicy = {0, NULL};
573 const CSSM_OID *utPolicyOid = NULL;
574 const char *utPolicyStr = NULL;
575 uint32 utPolicyStrLen = 0;
576 SecTrustSettingsKeyUsage utKeyUse = 0;
577 bool utTrustSettingEnabled = false;
578
579 if(VerifyContextResult) {
580 memset(VerifyContextResult, 0, sizeof(*VerifyContextResult));
581 }
582
583 /* verify input args, skipping the ones checked by CertGroupConstruct */
584 if((VerifyContext == NULL) || (VerifyContext->Cred == NULL)) {
585 /* the spec says that this is optional but we require it */
586 CssmError::throwMe(CSSMERR_TP_INVALID_REQUEST_INPUTS);
587 }
588 cred = VerifyContext->Cred;
589
590 /* Optional ActionData affecting all policies */
591 actionData = (CSSM_APPLE_TP_ACTION_DATA * volatile)VerifyContext->ActionData.Data;
592 if(actionData != NULL) {
593 switch(actionData->Version) {
594 case CSSM_APPLE_TP_ACTION_VERSION:
595 if(VerifyContext->ActionData.Length !=
596 sizeof(CSSM_APPLE_TP_ACTION_DATA)) {
597 CssmError::throwMe(CSSMERR_TP_INVALID_ACTION_DATA);
598 }
599 break;
600 /* handle backwards versions here if we ever go beyond version 0 */
601 default:
602 CssmError::throwMe(CSSMERR_TP_INVALID_ACTION_DATA);
603 }
604 actionFlags = actionData->ActionFlags;
605 if(actionFlags & CSSM_TP_ACTION_TRUST_SETTINGS) {
606 utTrustSettingEnabled = true;
607 }
608 }
609
610 /* optional, may be NULL */
611 cssmTimeStr = cred->VerifyTime;
612
613 tpStopOn = cred->VerificationAbortOn;
614 switch(tpStopOn) {
615 /* the only two we support */
616 case CSSM_TP_STOP_ON_NONE:
617 case CSSM_TP_STOP_ON_FIRST_FAIL:
618 break;
619 /* default maps to stop on first fail */
620 case CSSM_TP_STOP_ON_POLICY:
621 tpStopOn = CSSM_TP_STOP_ON_FIRST_FAIL;
622 break;
623 default:
624 CssmError::throwMe(CSSMERR_TP_INVALID_STOP_ON_POLICY);
625 }
626
627 /* now the args we can't deal with */
628 if(cred->CallerCredentials != NULL) {
629 CssmError::throwMe(CSSMERR_TP_INVALID_CALLERAUTH_CONTEXT_POINTER);
630 }
631 /* ...any others? */
632
633 /* set up for optional user trust evaluation */
634 if(utTrustSettingEnabled) {
635 const CSSM_TP_POLICYINFO *pinfo = &cred->Policy;
636 TPPolicy utPolicy = kTPx509Basic;
637
638 /* default policy OID in case caller hasn't specified one */
639 utPolicyOid = &utNullPolicy;
640 if(pinfo->NumberOfPolicyIds == 0) {
641 tpTrustSettingsDbg("CertGroupVerify: User trust enabled but no policies (1)");
642 /* keep going, I guess - no policy-specific info - use kTPx509Basic */
643 }
644 else {
645 CSSM_FIELD_PTR utPolicyField = &pinfo->PolicyIds[0];
646 utPolicyOid = &utPolicyField->FieldOid;
647 bool foundPolicy = checkPolicyOid(*utPolicyOid, utPolicy);
648 if(!foundPolicy) {
649 tpTrustSettingsDbg("CertGroupVerify: User trust enabled but no policies");
650 /* keep going, I guess - no policy-specific info - use kTPx509Basic */
651 }
652 else {
653 /* get policy-specific info */
654 tp_policyTrustSettingParams(utPolicy, &utPolicyField->FieldValue,
655 &utPolicyStr, &utPolicyStrLen, &utKeyUse);
656 }
657 }
658 }
659
660 /* get verified (possibly partial) outCertGroup - error is fatal */
661 /* BUT: we still return partial evidence if asked to...from now on. */
662 TPCertGroup outCertGroup(*this,
663 TGO_Caller); // certs are owned by inCertGroup
664 TPCertGroup inCertGroup(CertGroupToBeVerified, clHand, cspHand, *this,
665 cssmTimeStr, // optional 'this' time
666 true, // firstCertMustBeValid
667 TGO_Group);
668
669 /* set up for disposal of TPCertInfos created by CertGroupConstructPriv */
670 TPCertGroup gatheredCerts(*this, TGO_Group);
671
672 try {
673 CertGroupConstructPriv(
674 clHand,
675 cspHand,
676 inCertGroup,
677 cred->DBList,
678 cssmTimeStr,
679 cred->NumberOfAnchorCerts,
680 cred->AnchorCerts,
681 actionFlags,
682 utPolicyOid,
683 utPolicyStr,
684 utPolicyStrLen,
685 utKeyUse,
686 gatheredCerts,
687 verifiedToRoot,
688 verifiedToAnchor,
689 verifiedViaTrustSetting,
690 outCertGroup);
691 }
692 catch(const CssmError &cerr) {
693 constructReturn = cerr.error;
694 /* abort if no certs found */
695 if(outCertGroup.numCerts() == 0) {
696 CssmError::throwMe(constructReturn);
697 }
698 /* else press on, collecting as much info as we can */
699 }
700 /* others are way fatal */
701 assert(outCertGroup.numCerts() >= 1);
702
703 /* Infer interim status from return values */
704 switch(constructReturn) {
705 /* these values do not get overridden */
706 case CSSMERR_TP_CERTIFICATE_CANT_OPERATE:
707 case CSSMERR_TP_INVALID_CERT_AUTHORITY:
708 case CSSMERR_APPLETP_TRUST_SETTING_DENY:
709 case errSecInvalidTrustSettings:
710 break;
711 default:
712 /* infer status from these values... */
713 if(verifiedToAnchor || verifiedViaTrustSetting) {
714 /* full success; anchor doesn't have to be root */
715 constructReturn = CSSM_OK;
716 }
717 else if(verifiedToRoot) {
718 if(actionFlags & CSSM_TP_ACTION_IMPLICIT_ANCHORS) {
719 constructReturn = CSSM_OK;
720 }
721 else {
722 /* verified to root which is not an anchor */
723 constructReturn = CSSMERR_TP_INVALID_ANCHOR_CERT;
724 }
725 }
726 else {
727 /* partial chain, no root, not verifiable by anchor */
728 constructReturn = CSSMERR_TP_NOT_TRUSTED;
729 }
730
731 /*
732 * Those errors can be allowed, cert-chain-wide, per individual
733 * certs' allowedErrors
734 */
735 if((constructReturn != CSSM_OK) &&
736 outCertGroup.isAllowedError(constructReturn)) {
737 constructReturn = CSSM_OK;
738 }
739
740 /*
741 * Allow non-trusted root if whitelist check permits
742 */
743 if (constructReturn == CSSMERR_TP_NOT_TRUSTED) {
744 constructReturn = tpCheckCertificateAllowList(outCertGroup);
745 }
746 break;
747 }
748
749 /*
750 * Parameters passed to tp_policyVerify() and which vary per policy
751 * in the loop below
752 */
753 TPPolicy tpPolicy;
754 const CSSM_APPLE_TP_SSL_OPTIONS *sslOpts;
755 CSSM_RETURN thisPolicyRtn = CSSM_OK; // returned from tp_policyVerify()
756
757 /* common CRL verify parameters */
758 TPCrlGroup *crlGroup = NULL;
759 try {
760 crlGroup = new TPCrlGroup(&VerifyContext->Crls,
761 clHand, cspHand,
762 *this, // alloc
763 NULL, // cssmTimeStr - we want CRLs that are valid 'now'
764 TGO_Group);
765 }
766 catch(const CssmError &cerr) {
767 CSSM_RETURN cr = cerr.error;
768 /* I don't see a straightforward way to report this error,
769 * other than adding it to the leaf cert's status... */
770 outCertGroup.certAtIndex(0)->addStatusCode(cr);
771 tpDebug("CertGroupVerify: error constructing CrlGroup; continuing\n");
772 }
773 /* others are way fatal */
774
775 TPVerifyContext revokeVfyContext(*this,
776 clHand,
777 cspHand,
778 cssmTimeStr,
779 cred->NumberOfAnchorCerts,
780 cred->AnchorCerts,
781 &inCertGroup,
782 crlGroup,
783 /*
784 * This may consist of certs gathered from the net (which is the purpose
785 * of this argument) and from DLDBs (a side-effect optimization).
786 */
787 gatheredCerts,
788 cred->DBList,
789 kRevokeNone, // policy
790 actionFlags,
791 NULL, // CRL options
792 NULL, // OCSP options
793 utPolicyOid,
794 utPolicyStr,
795 utPolicyStrLen,
796 utKeyUse);
797
798 /* true if we're to execute tp_policyVerify at end of loop */
799 bool doPolicyVerify;
800 /* true if we're to execute a revocation policy at end of loop */
801 bool doRevocationPolicy;
802
803 /* grind thru each policy */
804 for(uint32 polDex=0; polDex<cred->Policy.NumberOfPolicyIds; polDex++) {
805 if(cred->Policy.PolicyIds == NULL) {
806 policyReturn = CSSMERR_TP_INVALID_POLICY_IDENTIFIERS;
807 break;
808 }
809 CSSM_FIELD_PTR policyId = &cred->Policy.PolicyIds[polDex];
810 const CSSM_DATA *fieldVal = &policyId->FieldValue;
811 const CSSM_OID *oid = &policyId->FieldOid;
812 thisPolicyRtn = CSSM_OK;
813 doPolicyVerify = false;
814 doRevocationPolicy = false;
815 sslOpts = NULL;
816
817 /* first the basic cert policies */
818 doPolicyVerify = checkPolicyOid(*oid, tpPolicy);
819 if(doPolicyVerify) {
820 /* some basic checks... */
821 bool policyAbort = false;
822 switch(tpPolicy) {
823 case kTPx509Basic:
824 case kTPiSign:
825 case kTP_PKINIT_Client:
826 case kTP_PKINIT_Server:
827 if(fieldVal->Data != NULL) {
828 policyReturn = CSSMERR_TP_INVALID_POLICY_IDENTIFIERS;
829 policyAbort = true;
830 break;
831 }
832 break;
833 default:
834 break;
835 }
836 if(policyAbort) {
837 break;
838 }
839 #if TP_PKINIT_SERVER_HACK
840 if(tpPolicy == kTP_PKINIT_Server) {
841 /* possible override of "root not in anchors" */
842 if(constructReturn == CSSMERR_TP_INVALID_ANCHOR_CERT) {
843 if(tpCheckPkinitServerCert(outCertGroup)) {
844 constructReturn = CSSM_OK;
845 }
846 }
847 }
848 #endif /* TP_PKINIT_SERVER_HACK */
849 }
850
851 /*
852 * Now revocation policies. Note some fields in revokeVfyContext can
853 * accumulate across multiple policy calls, e.g., signerCerts.
854 */
855 else if(tpCompareOids(oid, &CSSMOID_APPLE_TP_REVOCATION_CRL)) {
856 /* CRL-specific options */
857 const CSSM_APPLE_TP_CRL_OPTIONS *crlOpts;
858 crlOpts = (CSSM_APPLE_TP_CRL_OPTIONS *)fieldVal->Data;
859 thisPolicyRtn = CSSM_OK;
860 if(crlOpts != NULL) {
861 switch(crlOpts->Version) {
862 case CSSM_APPLE_TP_CRL_OPTS_VERSION:
863 if(fieldVal->Length !=
864 sizeof(CSSM_APPLE_TP_CRL_OPTIONS)) {
865 thisPolicyRtn =
866 CSSMERR_TP_INVALID_POLICY_IDENTIFIERS;
867 break;
868 }
869 break;
870 /* handle backwards compatibility here if necessary */
871 default:
872 thisPolicyRtn = CSSMERR_TP_INVALID_POLICY_IDENTIFIERS;
873 break;
874 }
875 if(thisPolicyRtn != CSSM_OK) {
876 policyReturn = thisPolicyRtn;
877 break;
878 }
879 }
880 revokeVfyContext.policy = kRevokeCrlBasic;
881 revokeVfyContext.crlOpts = crlOpts;
882 doRevocationPolicy = true;
883 }
884 else if(tpCompareOids(oid, &CSSMOID_APPLE_TP_REVOCATION_OCSP)) {
885 /* OCSP-specific options */
886 const CSSM_APPLE_TP_OCSP_OPTIONS *ocspOpts;
887 ocspOpts = (CSSM_APPLE_TP_OCSP_OPTIONS *)fieldVal->Data;
888 thisPolicyRtn = CSSM_OK;
889 if(ocspOpts != NULL) {
890 switch(ocspOpts->Version) {
891 case CSSM_APPLE_TP_OCSP_OPTS_VERSION:
892 if(fieldVal->Length !=
893 sizeof(CSSM_APPLE_TP_OCSP_OPTIONS)) {
894 thisPolicyRtn =
895 CSSMERR_TP_INVALID_POLICY_IDENTIFIERS;
896 break;
897 }
898 break;
899 /* handle backwards compatibility here if necessary */
900 default:
901 thisPolicyRtn = CSSMERR_TP_INVALID_POLICY_IDENTIFIERS;
902 break;
903 }
904 if(thisPolicyRtn != CSSM_OK) {
905 policyReturn = thisPolicyRtn;
906 break;
907 }
908 }
909 revokeVfyContext.policy = kRevokeOcsp;
910 revokeVfyContext.ocspOpts = ocspOpts;
911 doRevocationPolicy = true;
912 }
913 /* etc. - add more policies here */
914 else {
915 /* unknown TP policy OID */
916 policyReturn = CSSMERR_TP_INVALID_POLICY_IDENTIFIERS;
917 break;
918 }
919
920 /* common cert policy call */
921 if(doPolicyVerify) {
922 assert(!doRevocationPolicy); // one at a time
923 thisPolicyRtn = tp_policyVerify(tpPolicy,
924 *this,
925 clHand,
926 cspHand,
927 &outCertGroup,
928 verifiedToRoot,
929 verifiedViaTrustSetting,
930 actionFlags,
931 fieldVal,
932 cred->Policy.PolicyControl); // not currently used
933 didCertPolicy = true;
934 }
935 /* common revocation policy call */
936 if(doRevocationPolicy) {
937 assert(!doPolicyVerify); // one at a time
938 thisPolicyRtn = tpRevocationPolicyVerify(revokeVfyContext, outCertGroup);
939 didRevokePolicy = true;
940 }
941 /* See if possible error is allowed, cert-chain-wide. */
942 if((thisPolicyRtn != CSSM_OK) &&
943 outCertGroup.isAllowedError(thisPolicyRtn)) {
944 thisPolicyRtn = CSSM_OK;
945 }
946 if(thisPolicyRtn) {
947 /* Now remember the error if it's the first policy
948 * error we've seen. */
949 if(policyReturn == CSSM_OK) {
950 policyReturn = thisPolicyRtn;
951 }
952 /* Keep going? */
953 if(tpStopOn == CSSM_TP_STOP_ON_FIRST_FAIL) {
954 /* Nope; we're done with policy evaluation */
955 break;
956 }
957 }
958 } /* for each policy */
959
960 /*
961 * Upon completion of the above loop, perform default policy ops if
962 * appropriate.
963 */
964 if((policyReturn == CSSM_OK) || (tpStopOn == CSSM_TP_STOP_ON_NONE)) {
965 if(!didCertPolicy) {
966 policyReturn = tp_policyVerify(kTPDefault,
967 *this,
968 clHand,
969 cspHand,
970 &outCertGroup,
971 verifiedToRoot,
972 verifiedViaTrustSetting,
973 actionFlags,
974 NULL, // policyFieldData
975 cred->Policy.PolicyControl); // not currently used
976 /* See if error is allowed, cert-chain-wide. */
977 if((policyReturn != CSSM_OK) &&
978 outCertGroup.isAllowedError(policyReturn)) {
979 policyReturn = CSSM_OK;
980 }
981 }
982 if( !didRevokePolicy && // no revoke policy yet
983 ( (policyReturn == CSSM_OK || // default cert policy OK
984 (tpStopOn == CSSM_TP_STOP_ON_NONE)) // keep going anyway
985 )
986 ) {
987 revokeVfyContext.policy = TP_CRL_POLICY_DEFAULT;
988 CSSM_RETURN thisPolicyRtn = tpRevocationPolicyVerify(revokeVfyContext,
989 outCertGroup);
990 if((thisPolicyRtn != CSSM_OK) &&
991 outCertGroup.isAllowedError(thisPolicyRtn)) {
992 thisPolicyRtn = CSSM_OK;
993 }
994 if((thisPolicyRtn != CSSM_OK) && (policyReturn == CSSM_OK)) {
995 policyReturn = thisPolicyRtn;
996 }
997
998 }
999 } /* default policy opts */
1000
1001 delete crlGroup;
1002
1003 /* return evidence - i.e., constructed chain - if asked to */
1004 if(VerifyContextResult != NULL) {
1005 /*
1006 * VerifyContextResult->Evidence[0] : CSSM_TP_APPLE_EVIDENCE_HEADER
1007 * VerifyContextResult->Evidence[1] : CSSM_CERTGROUP
1008 * VerifyContextResult->Evidence[2] : CSSM_TP_APPLE_EVIDENCE_INFO
1009 */
1010 VerifyContextResult->NumberOfEvidences = 3;
1011 VerifyContextResult->Evidence =
1012 (CSSM_EVIDENCE_PTR)calloc(3, sizeof(CSSM_EVIDENCE));
1013
1014 CSSM_TP_APPLE_EVIDENCE_HEADER *hdr =
1015 (CSSM_TP_APPLE_EVIDENCE_HEADER *)malloc(
1016 sizeof(CSSM_TP_APPLE_EVIDENCE_HEADER));
1017 hdr->Version = CSSM_TP_APPLE_EVIDENCE_VERSION;
1018 CSSM_EVIDENCE_PTR ev = &VerifyContextResult->Evidence[0];
1019 ev->EvidenceForm = CSSM_EVIDENCE_FORM_APPLE_HEADER;
1020 ev->Evidence = hdr;
1021
1022 ev = &VerifyContextResult->Evidence[1];
1023 ev->EvidenceForm = CSSM_EVIDENCE_FORM_APPLE_CERTGROUP;
1024 ev->Evidence = outCertGroup.buildCssmCertGroup();
1025
1026 ev = &VerifyContextResult->Evidence[2];
1027 ev->EvidenceForm = CSSM_EVIDENCE_FORM_APPLE_CERT_INFO;
1028 ev->Evidence = outCertGroup.buildCssmEvidenceInfo();
1029 }
1030 else {
1031 /* caller responsible for freeing these if they are for evidence.... */
1032 outCertGroup.freeDbRecords();
1033 }
1034 CSSM_RETURN outErr = outCertGroup.getReturnCode(constructReturn, policyReturn,
1035 actionFlags);
1036
1037 if(outErr) {
1038 CssmError::throwMe(outErr);
1039 }
1040 }
1041
1042