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