1/* 2 * Copyright (c) 2000-2001, 2011 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 */ 55static 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 } 171errOut: 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/*----------------------------------------------------------------------------- 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 */ 231void 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 */ 302void 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 */ 379static 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 return false; 473} 474 475/*----------------------------------------------------------------------------- 476 * CertGroupVerify 477 * 478 * Description: 479 * -- Construct a cert chain using TP_CertGroupConstruct. 480 * -- Attempt to verify that cert chain against one of the known 481 * good certs passed in AnchorCerts. 482 * -- Optionally enforces additional policies (TBD) when verifying the cert chain. 483 * -- Optionally returns the entire cert chain constructed in 484 * TP_CertGroupConstruct and here, all the way to an anchor cert or as 485 * far as we were able to go, in *Evidence. 486 * 487 * Parameters: 488 * Two handles - to an open CL and CSP. The CSP must be capable of 489 * dealing with the signature algorithms used by the certs. The CL must be 490 * an X.509-savvy CL. 491 * 492 * RawCerts, an unordered array of raw certs in the form of a 493 * CSSM_CERTGROUP_PTR. The first cert of this list is the subject cert 494 * which is eventually to be verified. The other certs can be in any order 495 * and may not even have any relevance to the cert chain being constructed. 496 * They may also be invalid certs. 497 * 498 * DBList, a list of DB/DL handles which may contain certs necessary to 499 * complete the desired cert chain. (Currently not implemented.) 500 * 501 * AnchorCerts, a list of known trusted certs. 502 * NumberOfAnchorCerts, size of AnchorCerts array. 503 * 504 * PolicyIdentifiers, Optional policy OID. NULL indicates default 505 * X.509 trust policy. 506 * 507 * Supported Policies: 508 * CSSMOID_APPLE_ISIGN 509 * CSSMOID_APPLE_X509_BASIC 510 * 511 * For both of these, the associated FieldValue must be {0, NULL}, 512 * 513 * NumberOfPolicyIdentifiers, size of PolicyIdentifiers array, must be 514 * zero or one. 515 * 516 * All other arguments must be zero/NULL. 517 * 518 * Returns: 519 * CSSM_OK : cert chain verified all the way back to an AnchorCert. 520 * CSSMERR_TP_INVALID_ANCHOR_CERT : In this case, the cert chain 521 * was validated back to a self-signed (root) cert found in either 522 * CertToBeVerified or in one of the DBs in DBList, but that root cert 523 * was *NOT* found in the AnchorCert list. 524 * CSSMERR_TP_NOT_TRUSTED: no root cert was found and no AnchorCert 525 * verified the end of the constructed cert chain. 526 * CSSMERR_TP_VERIFICATION_FAILURE: a root cert was found which does 527 * not self-verify. 528 * CSSMERR_TP_VERIFY_ACTION_FAILED: indicates a failure of the requested 529 * policy action. 530 * CSSMERR_TP_INVALID_CERTIFICATE: indicates a bad leaf cert. 531 * CSSMERR_TP_INVALID_REQUEST_INPUTS : no incoming VerifyContext. 532 * CSSMERR_TP_CERT_EXPIRED and CSSMERR_TP_CERT_NOT_VALID_YET: see comments 533 * for CertGroupConstruct. 534 * CSSMERR_TP_CERTIFICATE_CANT_OPERATE : issuer cert was found with a partial 535 * public key, rendering full verification impossible. 536 * CSSMERR_TP_INVALID_CERT_AUTHORITY : issuer cert was found with a partial 537 * public key and which failed to perform subsequent signature 538 * verification. 539 *---------------------------------------------------------------------------*/ 540 541void AppleTPSession::CertGroupVerify(CSSM_CL_HANDLE clHand, 542 CSSM_CSP_HANDLE cspHand, 543 const CSSM_CERTGROUP &CertGroupToBeVerified, 544 const CSSM_TP_VERIFY_CONTEXT *VerifyContext, 545 CSSM_TP_VERIFY_CONTEXT_RESULT_PTR VerifyContextResult) 546{ 547 CSSM_BOOL verifiedToRoot = CSSM_FALSE; 548 CSSM_BOOL verifiedToAnchor = CSSM_FALSE; 549 CSSM_BOOL verifiedViaTrustSetting = CSSM_FALSE; 550 CSSM_RETURN constructReturn = CSSM_OK; 551 CSSM_RETURN policyReturn = CSSM_OK; 552 const CSSM_TP_CALLERAUTH_CONTEXT *cred; 553 /* declare volatile as compiler workaround to avoid caching in CR4 */ 554 const CSSM_APPLE_TP_ACTION_DATA * volatile actionData = NULL; 555 CSSM_TIMESTRING cssmTimeStr; 556 CSSM_APPLE_TP_ACTION_FLAGS actionFlags = 0; 557 CSSM_TP_STOP_ON tpStopOn = 0; 558 559 /* keep track of whether we did policy checking; if not, we do defaults */ 560 bool didCertPolicy = false; 561 bool didRevokePolicy = false; 562 563 /* user trust parameters */ 564 CSSM_OID utNullPolicy = {0, NULL}; 565 const CSSM_OID *utPolicyOid = NULL; 566 const char *utPolicyStr = NULL; 567 uint32 utPolicyStrLen = 0; 568 SecTrustSettingsKeyUsage utKeyUse = 0; 569 bool utTrustSettingEnabled = false; 570 571 if(VerifyContextResult) { 572 memset(VerifyContextResult, 0, sizeof(*VerifyContextResult)); 573 } 574 575 /* verify input args, skipping the ones checked by CertGroupConstruct */ 576 if((VerifyContext == NULL) || (VerifyContext->Cred == NULL)) { 577 /* the spec says that this is optional but we require it */ 578 CssmError::throwMe(CSSMERR_TP_INVALID_REQUEST_INPUTS); 579 } 580 cred = VerifyContext->Cred; 581 582 /* Optional ActionData affecting all policies */ 583 actionData = (CSSM_APPLE_TP_ACTION_DATA * volatile)VerifyContext->ActionData.Data; 584 if(actionData != NULL) { 585 switch(actionData->Version) { 586 case CSSM_APPLE_TP_ACTION_VERSION: 587 if(VerifyContext->ActionData.Length != 588 sizeof(CSSM_APPLE_TP_ACTION_DATA)) { 589 CssmError::throwMe(CSSMERR_TP_INVALID_ACTION_DATA); 590 } 591 break; 592 /* handle backwards versions here if we ever go beyond version 0 */ 593 default: 594 CssmError::throwMe(CSSMERR_TP_INVALID_ACTION_DATA); 595 } 596 actionFlags = actionData->ActionFlags; 597 if(actionFlags & CSSM_TP_ACTION_TRUST_SETTINGS) { 598 utTrustSettingEnabled = true; 599 } 600 } 601 602 /* optional, may be NULL */ 603 cssmTimeStr = cred->VerifyTime; 604 605 tpStopOn = cred->VerificationAbortOn; 606 switch(tpStopOn) { 607 /* the only two we support */ 608 case CSSM_TP_STOP_ON_NONE: 609 case CSSM_TP_STOP_ON_FIRST_FAIL: 610 break; 611 /* default maps to stop on first fail */ 612 case CSSM_TP_STOP_ON_POLICY: 613 tpStopOn = CSSM_TP_STOP_ON_FIRST_FAIL; 614 break; 615 default: 616 CssmError::throwMe(CSSMERR_TP_INVALID_STOP_ON_POLICY); 617 } 618 619 /* now the args we can't deal with */ 620 if(cred->CallerCredentials != NULL) { 621 CssmError::throwMe(CSSMERR_TP_INVALID_CALLERAUTH_CONTEXT_POINTER); 622 } 623 /* ...any others? */ 624 625 /* set up for optional user trust evaluation */ 626 if(utTrustSettingEnabled) { 627 const CSSM_TP_POLICYINFO *pinfo = &cred->Policy; 628 TPPolicy utPolicy = kTPx509Basic; 629 630 /* default policy OID in case caller hasn't specified one */ 631 utPolicyOid = &utNullPolicy; 632 if(pinfo->NumberOfPolicyIds == 0) { 633 tpTrustSettingsDbg("CertGroupVerify: User trust enabled but no policies (1)"); 634 /* keep going, I guess - no policy-specific info - use kTPx509Basic */ 635 } 636 else { 637 CSSM_FIELD_PTR utPolicyField = &pinfo->PolicyIds[0]; 638 utPolicyOid = &utPolicyField->FieldOid; 639 bool foundPolicy = checkPolicyOid(*utPolicyOid, utPolicy); 640 if(!foundPolicy) { 641 tpTrustSettingsDbg("CertGroupVerify: User trust enabled but no policies"); 642 /* keep going, I guess - no policy-specific info - use kTPx509Basic */ 643 } 644 else { 645 /* get policy-specific info */ 646 tp_policyTrustSettingParams(utPolicy, &utPolicyField->FieldValue, 647 &utPolicyStr, &utPolicyStrLen, &utKeyUse); 648 } 649 } 650 } 651 652 /* get verified (possibly partial) outCertGroup - error is fatal */ 653 /* BUT: we still return partial evidence if asked to...from now on. */ 654 TPCertGroup outCertGroup(*this, 655 TGO_Caller); // certs are owned by inCertGroup 656 TPCertGroup inCertGroup(CertGroupToBeVerified, clHand, cspHand, *this, 657 cssmTimeStr, // optional 'this' time 658 true, // firstCertMustBeValid 659 TGO_Group); 660 661 /* set up for disposal of TPCertInfos created by CertGroupConstructPriv */ 662 TPCertGroup gatheredCerts(*this, TGO_Group); 663 664 try { 665 CertGroupConstructPriv( 666 clHand, 667 cspHand, 668 inCertGroup, 669 cred->DBList, 670 cssmTimeStr, 671 cred->NumberOfAnchorCerts, 672 cred->AnchorCerts, 673 actionFlags, 674 utPolicyOid, 675 utPolicyStr, 676 utPolicyStrLen, 677 utKeyUse, 678 gatheredCerts, 679 verifiedToRoot, 680 verifiedToAnchor, 681 verifiedViaTrustSetting, 682 outCertGroup); 683 } 684 catch(const CssmError &cerr) { 685 constructReturn = cerr.error; 686 /* abort if no certs found */ 687 if(outCertGroup.numCerts() == 0) { 688 CssmError::throwMe(constructReturn); 689 } 690 /* else press on, collecting as much info as we can */ 691 } 692 /* others are way fatal */ 693 assert(outCertGroup.numCerts() >= 1); 694 695 /* Infer interim status from return values */ 696 switch(constructReturn) { 697 /* these values do not get overridden */ 698 case CSSMERR_TP_CERTIFICATE_CANT_OPERATE: 699 case CSSMERR_TP_INVALID_CERT_AUTHORITY: 700 case CSSMERR_APPLETP_TRUST_SETTING_DENY: 701 case errSecInvalidTrustSettings: 702 break; 703 default: 704 /* infer status from these values... */ 705 if(verifiedToAnchor || verifiedViaTrustSetting) { 706 /* full success; anchor doesn't have to be root */ 707 constructReturn = CSSM_OK; 708 } 709 else if(verifiedToRoot) { 710 if(actionFlags & CSSM_TP_ACTION_IMPLICIT_ANCHORS) { 711 constructReturn = CSSM_OK; 712 } 713 else { 714 /* verified to root which is not an anchor */ 715 constructReturn = CSSMERR_TP_INVALID_ANCHOR_CERT; 716 } 717 } 718 else { 719 /* partial chain, no root, not verifiable by anchor */ 720 constructReturn = CSSMERR_TP_NOT_TRUSTED; 721 } 722 723 /* 724 * Those errors can be allowed, cert-chain-wide, per individual 725 * certs' allowedErrors 726 */ 727 if((constructReturn != CSSM_OK) && 728 outCertGroup.isAllowedError(constructReturn)) { 729 constructReturn = CSSM_OK; 730 } 731 break; 732 } 733 734 /* 735 * Parameters passed to tp_policyVerify() and which vary per policy 736 * in the loop below 737 */ 738 TPPolicy tpPolicy; 739 const CSSM_APPLE_TP_SSL_OPTIONS *sslOpts; 740 CSSM_RETURN thisPolicyRtn = CSSM_OK; // returned from tp_policyVerify() 741 742 /* common CRL verify parameters */ 743 TPCrlGroup *crlGroup = NULL; 744 try { 745 crlGroup = new TPCrlGroup(&VerifyContext->Crls, 746 clHand, cspHand, 747 *this, // alloc 748 NULL, // cssmTimeStr - we want CRLs that are valid 'now' 749 TGO_Group); 750 } 751 catch(const CssmError &cerr) { 752 CSSM_RETURN cr = cerr.error; 753 /* I don't see a straightforward way to report this error, 754 * other than adding it to the leaf cert's status... */ 755 outCertGroup.certAtIndex(0)->addStatusCode(cr); 756 tpDebug("CertGroupVerify: error constructing CrlGroup; continuing\n"); 757 } 758 /* others are way fatal */ 759 760 TPVerifyContext revokeVfyContext(*this, 761 clHand, 762 cspHand, 763 cssmTimeStr, 764 cred->NumberOfAnchorCerts, 765 cred->AnchorCerts, 766 &inCertGroup, 767 crlGroup, 768 /* 769 * This may consist of certs gathered from the net (which is the purpose 770 * of this argument) and from DLDBs (a side-effect optimization). 771 */ 772 gatheredCerts, 773 cred->DBList, 774 kRevokeNone, // policy 775 actionFlags, 776 NULL, // CRL options 777 NULL, // OCSP options 778 utPolicyOid, 779 utPolicyStr, 780 utPolicyStrLen, 781 utKeyUse); 782 783 /* true if we're to execute tp_policyVerify at end of loop */ 784 bool doPolicyVerify; 785 /* true if we're to execute a revocation policy at end of loop */ 786 bool doRevocationPolicy; 787 788 /* grind thru each policy */ 789 for(uint32 polDex=0; polDex<cred->Policy.NumberOfPolicyIds; polDex++) { 790 if(cred->Policy.PolicyIds == NULL) { 791 policyReturn = CSSMERR_TP_INVALID_POLICY_IDENTIFIERS; 792 break; 793 } 794 CSSM_FIELD_PTR policyId = &cred->Policy.PolicyIds[polDex]; 795 const CSSM_DATA *fieldVal = &policyId->FieldValue; 796 const CSSM_OID *oid = &policyId->FieldOid; 797 thisPolicyRtn = CSSM_OK; 798 doPolicyVerify = false; 799 doRevocationPolicy = false; 800 sslOpts = NULL; 801 802 /* first the basic cert policies */ 803 doPolicyVerify = checkPolicyOid(*oid, tpPolicy); 804 if(doPolicyVerify) { 805 /* some basic checks... */ 806 bool policyAbort = false; 807 switch(tpPolicy) { 808 case kTPx509Basic: 809 case kTPiSign: 810 case kTP_PKINIT_Client: 811 case kTP_PKINIT_Server: 812 if(fieldVal->Data != NULL) { 813 policyReturn = CSSMERR_TP_INVALID_POLICY_IDENTIFIERS; 814 policyAbort = true; 815 break; 816 } 817 break; 818 default: 819 break; 820 } 821 if(policyAbort) { 822 break; 823 } 824 #if TP_PKINIT_SERVER_HACK 825 if(tpPolicy == kTP_PKINIT_Server) { 826 /* possible override of "root not in anchors" */ 827 if(constructReturn == CSSMERR_TP_INVALID_ANCHOR_CERT) { 828 if(tpCheckPkinitServerCert(outCertGroup)) { 829 constructReturn = CSSM_OK; 830 } 831 } 832 } 833 #endif /* TP_PKINIT_SERVER_HACK */ 834 } 835 836 /* 837 * Now revocation policies. Note some fields in revokeVfyContext can 838 * accumulate across multiple policy calls, e.g., signerCerts. 839 */ 840 else if(tpCompareOids(oid, &CSSMOID_APPLE_TP_REVOCATION_CRL)) { 841 /* CRL-specific options */ 842 const CSSM_APPLE_TP_CRL_OPTIONS *crlOpts; 843 crlOpts = (CSSM_APPLE_TP_CRL_OPTIONS *)fieldVal->Data; 844 thisPolicyRtn = CSSM_OK; 845 if(crlOpts != NULL) { 846 switch(crlOpts->Version) { 847 case CSSM_APPLE_TP_CRL_OPTS_VERSION: 848 if(fieldVal->Length != 849 sizeof(CSSM_APPLE_TP_CRL_OPTIONS)) { 850 thisPolicyRtn = 851 CSSMERR_TP_INVALID_POLICY_IDENTIFIERS; 852 break; 853 } 854 break; 855 /* handle backwards compatibility here if necessary */ 856 default: 857 thisPolicyRtn = CSSMERR_TP_INVALID_POLICY_IDENTIFIERS; 858 break; 859 } 860 if(thisPolicyRtn != CSSM_OK) { 861 policyReturn = thisPolicyRtn; 862 break; 863 } 864 } 865 revokeVfyContext.policy = kRevokeCrlBasic; 866 revokeVfyContext.crlOpts = crlOpts; 867 doRevocationPolicy = true; 868 } 869 else if(tpCompareOids(oid, &CSSMOID_APPLE_TP_REVOCATION_OCSP)) { 870 /* OCSP-specific options */ 871 const CSSM_APPLE_TP_OCSP_OPTIONS *ocspOpts; 872 ocspOpts = (CSSM_APPLE_TP_OCSP_OPTIONS *)fieldVal->Data; 873 thisPolicyRtn = CSSM_OK; 874 if(ocspOpts != NULL) { 875 switch(ocspOpts->Version) { 876 case CSSM_APPLE_TP_OCSP_OPTS_VERSION: 877 if(fieldVal->Length != 878 sizeof(CSSM_APPLE_TP_OCSP_OPTIONS)) { 879 thisPolicyRtn = 880 CSSMERR_TP_INVALID_POLICY_IDENTIFIERS; 881 break; 882 } 883 break; 884 /* handle backwards compatibility here if necessary */ 885 default: 886 thisPolicyRtn = CSSMERR_TP_INVALID_POLICY_IDENTIFIERS; 887 break; 888 } 889 if(thisPolicyRtn != CSSM_OK) { 890 policyReturn = thisPolicyRtn; 891 break; 892 } 893 } 894 revokeVfyContext.policy = kRevokeOcsp; 895 revokeVfyContext.ocspOpts = ocspOpts; 896 doRevocationPolicy = true; 897 } 898 /* etc. - add more policies here */ 899 else { 900 /* unknown TP policy OID */ 901 policyReturn = CSSMERR_TP_INVALID_POLICY_IDENTIFIERS; 902 break; 903 } 904 905 /* common cert policy call */ 906 if(doPolicyVerify) { 907 assert(!doRevocationPolicy); // one at a time 908 thisPolicyRtn = tp_policyVerify(tpPolicy, 909 *this, 910 clHand, 911 cspHand, 912 &outCertGroup, 913 verifiedToRoot, 914 verifiedViaTrustSetting, 915 actionFlags, 916 fieldVal, 917 cred->Policy.PolicyControl); // not currently used 918 didCertPolicy = true; 919 } 920 /* common revocation policy call */ 921 if(doRevocationPolicy) { 922 assert(!doPolicyVerify); // one at a time 923 thisPolicyRtn = tpRevocationPolicyVerify(revokeVfyContext, outCertGroup); 924 didRevokePolicy = true; 925 } 926 /* See if possible error is allowed, cert-chain-wide. */ 927 if((thisPolicyRtn != CSSM_OK) && 928 outCertGroup.isAllowedError(thisPolicyRtn)) { 929 thisPolicyRtn = CSSM_OK; 930 } 931 if(thisPolicyRtn) { 932 /* Now remember the error if it's the first policy 933 * error we've seen. */ 934 if(policyReturn == CSSM_OK) { 935 policyReturn = thisPolicyRtn; 936 } 937 /* Keep going? */ 938 if(tpStopOn == CSSM_TP_STOP_ON_FIRST_FAIL) { 939 /* Nope; we're done with policy evaluation */ 940 break; 941 } 942 } 943 } /* for each policy */ 944 945 /* 946 * Upon completion of the above loop, perform default policy ops if 947 * appropriate. 948 */ 949 if((policyReturn == CSSM_OK) || (tpStopOn == CSSM_TP_STOP_ON_NONE)) { 950 if(!didCertPolicy) { 951 policyReturn = tp_policyVerify(kTPDefault, 952 *this, 953 clHand, 954 cspHand, 955 &outCertGroup, 956 verifiedToRoot, 957 verifiedViaTrustSetting, 958 actionFlags, 959 NULL, // policyFieldData 960 cred->Policy.PolicyControl); // not currently used 961 /* See if error is allowed, cert-chain-wide. */ 962 if((policyReturn != CSSM_OK) && 963 outCertGroup.isAllowedError(policyReturn)) { 964 policyReturn = CSSM_OK; 965 } 966 } 967 if( !didRevokePolicy && // no revoke policy yet 968 ( (policyReturn == CSSM_OK || // default cert policy OK 969 (tpStopOn == CSSM_TP_STOP_ON_NONE)) // keep going anyway 970 ) 971 ) { 972 revokeVfyContext.policy = TP_CRL_POLICY_DEFAULT; 973 CSSM_RETURN thisPolicyRtn = tpRevocationPolicyVerify(revokeVfyContext, 974 outCertGroup); 975 if((thisPolicyRtn != CSSM_OK) && 976 outCertGroup.isAllowedError(thisPolicyRtn)) { 977 thisPolicyRtn = CSSM_OK; 978 } 979 if((thisPolicyRtn != CSSM_OK) && (policyReturn == CSSM_OK)) { 980 policyReturn = thisPolicyRtn; 981 } 982 983 } 984 } /* default policy opts */ 985 986 delete crlGroup; 987 988 /* return evidence - i.e., constructed chain - if asked to */ 989 if(VerifyContextResult != NULL) { 990 /* 991 * VerifyContextResult->Evidence[0] : CSSM_TP_APPLE_EVIDENCE_HEADER 992 * VerifyContextResult->Evidence[1] : CSSM_CERTGROUP 993 * VerifyContextResult->Evidence[2] : CSSM_TP_APPLE_EVIDENCE_INFO 994 */ 995 VerifyContextResult->NumberOfEvidences = 3; 996 VerifyContextResult->Evidence = 997 (CSSM_EVIDENCE_PTR)calloc(3, sizeof(CSSM_EVIDENCE)); 998 999 CSSM_TP_APPLE_EVIDENCE_HEADER *hdr = 1000 (CSSM_TP_APPLE_EVIDENCE_HEADER *)malloc( 1001 sizeof(CSSM_TP_APPLE_EVIDENCE_HEADER)); 1002 hdr->Version = CSSM_TP_APPLE_EVIDENCE_VERSION; 1003 CSSM_EVIDENCE_PTR ev = &VerifyContextResult->Evidence[0]; 1004 ev->EvidenceForm = CSSM_EVIDENCE_FORM_APPLE_HEADER; 1005 ev->Evidence = hdr; 1006 1007 ev = &VerifyContextResult->Evidence[1]; 1008 ev->EvidenceForm = CSSM_EVIDENCE_FORM_APPLE_CERTGROUP; 1009 ev->Evidence = outCertGroup.buildCssmCertGroup(); 1010 1011 ev = &VerifyContextResult->Evidence[2]; 1012 ev->EvidenceForm = CSSM_EVIDENCE_FORM_APPLE_CERT_INFO; 1013 ev->Evidence = outCertGroup.buildCssmEvidenceInfo(); 1014 } 1015 else { 1016 /* caller responsible for freeing these if they are for evidence.... */ 1017 outCertGroup.freeDbRecords(); 1018 } 1019 CSSM_RETURN outErr = outCertGroup.getReturnCode(constructReturn, policyReturn, 1020 actionFlags); 1021 1022 if(outErr) { 1023 CssmError::throwMe(outErr); 1024 } 1025} 1026 1027 1028