TrustSettings.cpp
1 /* 2 * Copyright (c) 2005,2011-2015 Apple Inc. All Rights Reserved. 3 * 4 * @APPLE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. Please obtain a copy of the License at 10 * http://www.opensource.apple.com/apsl/ and read it before using this 11 * file. 12 * 13 * The Original Code and all software distributed under the License are 14 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 * Please see the License for the specific language governing rights and 19 * limitations under the License. 20 * 21 * @APPLE_LICENSE_HEADER_END@ 22 */ 23 24 /* 25 * TrustSettings.h - class to manage cert trust settings. 26 * 27 */ 28 29 #include "TrustSettings.h" 30 #include "TrustSettingsSchema.h" 31 #include <Security/SecTrustSettings.h> 32 #include "TrustSettingsUtils.h" 33 #include "TrustKeychains.h" 34 #include "Certificate.h" 35 #include "cssmdatetime.h" 36 #include <Security/SecBase.h> 37 #include "SecTrustedApplicationPriv.h" 38 #include <security_utilities/errors.h> 39 #include <security_utilities/debugging.h> 40 #include <security_utilities/logging.h> 41 #include <security_utilities/cfutilities.h> 42 #include <security_utilities/alloc.h> 43 #include <security_utilities/casts.h> 44 #include <utilities/SecCFRelease.h> 45 #include <Security/Authorization.h> 46 #include <Security/cssmapplePriv.h> 47 #include <Security/oidscert.h> 48 #include <Security/SecCertificatePriv.h> 49 #include <Security/SecPolicyPriv.h> 50 #include <security_keychain/KCCursor.h> 51 #include <security_ocspd/ocspdClient.h> 52 #include <CoreFoundation/CoreFoundation.h> 53 #include <security_utilities/simulatecrash_assert.h> 54 #include <dispatch/dispatch.h> 55 #include <sys/stat.h> 56 #include <syslog.h> 57 58 #if 0 59 #define trustSettingsDbg(args...) syslog(LOG_ERR, ## args) 60 #define trustSettingsEvalDbg(args...) syslog(LOG_ERR, ## args) 61 #else 62 #define trustSettingsDbg(args...) secinfo("trustSettings", ## args) 63 #define trustSettingsEvalDbg(args...) secinfo("trustSettingsEval", ## args) 64 #endif 65 66 /* 67 * Common error return for "malformed TrustSettings record" 68 */ 69 #define errSecInvalidTrustedRootRecord errSecInvalidTrustSettings 70 71 using namespace KeychainCore; 72 73 #pragma mark --- Static functions --- 74 75 /* 76 * Comparator atoms to determine if an app's specified usage 77 * matches an individual trust setting. Each returns true on a match, false 78 * if the trust setting does not match the app's spec. 79 * 80 * A match fails iff: 81 * 82 * -- the app has specified a field, and the cert has a spec for that 83 * field, and the two specs do not match; 84 * 85 * OR 86 * 87 * -- the cert has a spec for the field and the app hasn't specified the field 88 */ 89 static bool tsCheckPolicy( 90 const CSSM_OID *appPolicy, 91 CFDataRef certPolicy) 92 { 93 if(certPolicy != NULL) { 94 if(appPolicy == NULL) { 95 trustSettingsEvalDbg("tsCheckPolicy: certPolicy, !appPolicy"); 96 return false; 97 } 98 unsigned cLen = (unsigned)CFDataGetLength(certPolicy); 99 const UInt8 *cData = CFDataGetBytePtr(certPolicy); 100 if((cLen != appPolicy->Length) || memcmp(appPolicy->Data, cData, cLen)) { 101 trustSettingsEvalDbg("tsCheckPolicy: policy mismatch"); 102 return false; 103 } 104 } 105 return true; 106 } 107 108 /* 109 * This one's slightly different: the match is for *this* app, not one 110 * specified by the app. 111 */ 112 static bool tsCheckApp( 113 CFDataRef certApp) 114 { 115 if(certApp != NULL) { 116 SecTrustedApplicationRef appRef; 117 OSStatus ortn; 118 ortn = SecTrustedApplicationCreateWithExternalRepresentation(certApp, &appRef); 119 if(ortn) { 120 trustSettingsDbg("tsCheckApp: bad trustedApp data"); 121 return false; 122 } 123 ortn = SecTrustedApplicationValidateWithPath(appRef, NULL); 124 if(ortn) { 125 /* Not this app */ 126 return false; 127 } 128 } 129 130 return true; 131 } 132 133 static bool tsCheckKeyUse( 134 SecTrustSettingsKeyUsage appKeyUse, 135 CFNumberRef certKeyUse) 136 { 137 if(certKeyUse != NULL) { 138 SInt32 certUse; 139 CFNumberGetValue(certKeyUse, kCFNumberSInt32Type, &certUse); 140 SecTrustSettingsKeyUsage cku = (SecTrustSettingsKeyUsage)certUse; 141 if(cku == kSecTrustSettingsKeyUseAny) { 142 /* explicitly allows anything */ 143 return true; 144 } 145 /* cert specification must be a superset of app's intended use */ 146 if(appKeyUse == 0) { 147 trustSettingsEvalDbg("tsCheckKeyUse: certKeyUsage, !appKeyUsage"); 148 return false; 149 } 150 151 if((cku & appKeyUse) != appKeyUse) { 152 trustSettingsEvalDbg("tsCheckKeyUse: keyUse mismatch"); 153 return false; 154 } 155 } 156 return true; 157 } 158 159 static bool tsCheckPolicyStr( 160 const char *appPolicyStr, 161 CFStringRef certPolicyStr) 162 { 163 if(certPolicyStr != NULL) { 164 if(appPolicyStr == NULL) { 165 trustSettingsEvalDbg("tsCheckPolicyStr: certPolicyStr, !appPolicyStr"); 166 return false; 167 } 168 /* Let CF do the string compare */ 169 CFStringRef cfPolicyStr = CFStringCreateWithCString(NULL, appPolicyStr, 170 kCFStringEncodingUTF8); 171 if(cfPolicyStr == NULL) { 172 /* I really don't see how this can happen */ 173 trustSettingsEvalDbg("tsCheckPolicyStr: policyStr string conversion error"); 174 return false; 175 } 176 177 // Some trust setting strings were created with a NULL character at the 178 // end, which was included in the length. Strip those off before compare 179 180 CFMutableStringRef certPolicyStrNoNULL = CFStringCreateMutableCopy(NULL, 0, certPolicyStr); 181 if (certPolicyStrNoNULL == NULL) { 182 /* I really don't see how this can happen either */ 183 trustSettingsEvalDbg("tsCheckPolicyStr: policyStr string conversion error 2"); 184 CFReleaseNull(cfPolicyStr); 185 return false; 186 } 187 188 CFStringFindAndReplace(certPolicyStrNoNULL, CFSTR("\00"), 189 CFSTR(""), CFRangeMake(0, CFStringGetLength(certPolicyStrNoNULL)), kCFCompareBackwards); 190 191 CFComparisonResult res = CFStringCompare(cfPolicyStr, certPolicyStrNoNULL, 0); 192 CFRelease(cfPolicyStr); 193 CFRelease(certPolicyStrNoNULL); 194 if(res != kCFCompareEqualTo) { 195 trustSettingsEvalDbg("tsCheckPolicyStr: policyStr mismatch"); 196 return false; 197 } 198 } 199 return true; 200 } 201 202 /* 203 * Determine if a cert's trust settings dictionary satisfies the specified 204 * usage constraints. Returns true if so. 205 * Only certs with a SecTrustSettingsResult of kSecTrustSettingsResultTrustRoot 206 * or kSecTrustSettingsResultTrustAsRoot will match. 207 */ 208 static bool qualifyUsageWithCertDict( 209 CFDictionaryRef certDict, 210 const CSSM_OID *policyOID, /* optional */ 211 const char *policyStr, /* optional */ 212 SecTrustSettingsKeyUsage keyUsage, /* optional; default = any (actually "all" here) */ 213 bool onlyRoots) 214 { 215 /* this array is optional */ 216 CFArrayRef trustSettings = (CFArrayRef)CFDictionaryGetValue(certDict, 217 kTrustRecordTrustSettings); 218 CFIndex numSpecs = 0; 219 if(trustSettings != NULL) { 220 numSpecs = CFArrayGetCount(trustSettings); 221 } 222 if(numSpecs == 0) { 223 /* 224 * Trivial case: cert has no trust settings, indicating that 225 * it's used for everything. 226 */ 227 trustSettingsEvalDbg("qualifyUsageWithCertDict: no trust settings"); 228 return true; 229 } 230 for(CFIndex addDex=0; addDex<numSpecs; addDex++) { 231 CFDictionaryRef tsDict = (CFDictionaryRef)CFArrayGetValueAtIndex(trustSettings, 232 addDex); 233 234 /* per-cert specs: all optional */ 235 CFDataRef certPolicy = (CFDataRef)CFDictionaryGetValue(tsDict, 236 kSecTrustSettingsPolicy); 237 CFDataRef certApp = (CFDataRef)CFDictionaryGetValue(tsDict, 238 kSecTrustSettingsApplication); 239 CFStringRef certPolicyStr = (CFStringRef)CFDictionaryGetValue(tsDict, 240 kSecTrustSettingsPolicyString); 241 CFNumberRef certKeyUsage = (CFNumberRef)CFDictionaryGetValue(tsDict, 242 kSecTrustSettingsKeyUsage); 243 CFNumberRef certResultType = (CFNumberRef)CFDictionaryGetValue(tsDict, 244 kSecTrustSettingsResult); 245 246 if(!tsCheckPolicy(policyOID, certPolicy)) { 247 continue; 248 } 249 if(!tsCheckApp(certApp)) { 250 continue; 251 } 252 if(!tsCheckKeyUse(keyUsage, certKeyUsage)) { 253 continue; 254 } 255 if(!tsCheckPolicyStr(policyStr, certPolicyStr)) { 256 continue; 257 } 258 259 /* 260 * This is a match, take whatever SecTrustSettingsResult is here, 261 * including the default if not specified. 262 */ 263 SecTrustSettingsResult resultType = kSecTrustSettingsResultTrustRoot; 264 if(certResultType) { 265 SInt32 s; 266 CFNumberGetValue(certResultType, kCFNumberSInt32Type, &s); 267 resultType = (SecTrustSettingsResult)s; 268 } 269 switch(resultType) { 270 case kSecTrustSettingsResultTrustRoot: 271 trustSettingsEvalDbg("qualifyUsageWithCertDict: TrustRoot MATCH"); 272 return true; 273 case kSecTrustSettingsResultTrustAsRoot: 274 if(onlyRoots) { 275 trustSettingsEvalDbg("qualifyUsageWithCertDict: TrustAsRoot but not root"); 276 return false; 277 } 278 trustSettingsEvalDbg("qualifyUsageWithCertDict: TrustAsRoot MATCH"); 279 return true; 280 default: 281 trustSettingsEvalDbg("qualifyUsageWithCertDict: bad resultType " 282 "(%lu)", (unsigned long)resultType); 283 return false; 284 } 285 } 286 trustSettingsEvalDbg("qualifyUsageWithCertDict: NO MATCH"); 287 return false; 288 } 289 290 /* 291 * Create initial top-level dictionary when constructing a new TrustSettings. 292 */ 293 static CFMutableDictionaryRef tsInitialDict() 294 { 295 CFMutableDictionaryRef dict = CFDictionaryCreateMutable(NULL, 296 kSecTrustRecordNumTopDictKeys, 297 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 298 299 /* the dictionary of per-cert entries */ 300 CFMutableDictionaryRef trustDict = CFDictionaryCreateMutable(NULL, 0, 301 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 302 CFDictionaryAddValue(dict, kTrustRecordTrustList, trustDict); 303 CFRelease(trustDict); 304 305 SInt32 vers = kSecTrustRecordVersionCurrent; 306 CFNumberRef cfVers = CFNumberCreate(NULL, kCFNumberSInt32Type, &vers); 307 CFDictionaryAddValue(dict, kTrustRecordVersion, cfVers); 308 CFRelease(cfVers); 309 return dict; 310 } 311 312 /* 313 * Set the modification date of a per-cert dictionary to current time. 314 */ 315 static void tsSetModDate( 316 CFMutableDictionaryRef dict) 317 { 318 CFDateRef modDate; 319 320 modDate = CFDateCreate(NULL, CFAbsoluteTimeGetCurrent()); 321 CFDictionarySetValue(dict, kTrustRecordModDate, modDate); 322 CFRelease(modDate); 323 } 324 325 /* make sure a presumed CFNumber can be converted to a 32-bit number */ 326 static 327 bool tsIsGoodCfNum(CFNumberRef cfn, SInt32 *num = NULL) 328 { 329 if(cfn == NULL) { 330 /* by convention */ 331 if(num) { 332 *num = 0; 333 } 334 return true; 335 } 336 if(CFGetTypeID(cfn) != CFNumberGetTypeID()) { 337 return false; 338 } 339 340 SInt32 s; 341 if(!CFNumberGetValue(cfn, kCFNumberSInt32Type, &s)) { 342 return false; 343 } 344 else { 345 if(num) { 346 *num = s; 347 } 348 return true; 349 } 350 } 351 352 TrustSettings::TrustSettings(SecTrustSettingsDomain domain) 353 : mPropList(NULL), 354 mTrustDict(NULL), 355 mDictVersion(0), 356 mDomain(domain), 357 mDirty(false) 358 { 359 } 360 361 362 363 #pragma mark --- Public methods --- 364 365 /* 366 * Normal constructor, from disk. 367 * If create is true, the absence of an on-disk TrustSettings file 368 * results in the creation of a new empty TrustSettings. If create is 369 * false and no on-disk TrustSettings exists, errSecNoTrustSettings is 370 * thrown. 371 * If trim is true, the components of the on-disk TrustSettings not 372 * needed for cert evaluation are discarded. This is for TrustSettings 373 * that will be cached in memory long-term. 374 */ 375 OSStatus TrustSettings::CreateTrustSettings( 376 SecTrustSettingsDomain domain, 377 bool create, 378 bool trim, 379 TrustSettings*& ts) 380 { 381 TrustSettings* t = new TrustSettings(domain); 382 383 Allocator &alloc = Allocator::standard(); 384 CSSM_DATA fileData = {0, NULL}; 385 OSStatus ortn = errSecSuccess; 386 struct stat sb; 387 const char *path; 388 389 /* get trust settings from file, one way or another */ 390 switch(domain) { 391 case kSecTrustSettingsDomainAdmin: 392 /* 393 * Quickie optimization: if it's not there, don't try to 394 * get it from ocspd. This is possible because the name of the 395 * admin file is hard coded, but the per-user files aren't. 396 */ 397 path = TRUST_SETTINGS_PATH "/" ADMIN_TRUST_SETTINGS; 398 if(stat(path, &sb)) { 399 trustSettingsDbg("TrustSettings: no admin record; skipping"); 400 ortn = errSecNoTrustSettings; 401 break; 402 } 403 /* else drop thru, get it from ocspd */ 404 case kSecTrustSettingsDomainUser: 405 /* get settings from ocspd */ 406 ortn = ocspdTrustSettingsRead(alloc, domain, fileData); 407 break; 408 case kSecTrustSettingsDomainSystem: 409 /* immutable; it's safe for us to read this directly */ 410 if(tsReadFile(SYSTEM_TRUST_SETTINGS_PATH, alloc, fileData)) { 411 ortn = errSecNoTrustSettings; 412 } 413 break; 414 default: 415 delete t; 416 return errSecParam; 417 } 418 if(ortn) { 419 if(create) { 420 trustSettingsDbg("TrustSettings: creating new record for domain %d", 421 (int)domain); 422 t->mPropList = tsInitialDict(); 423 t->mDirty = true; 424 } 425 else { 426 trustSettingsDbg("TrustSettings: record not found for domain %d", 427 (int)domain); 428 delete t; 429 return ortn; 430 } 431 } 432 else { 433 CFRef<CFDataRef> propList(CFDataCreate(NULL, fileData.Data, fileData.Length)); 434 t->initFromData(propList); 435 alloc.free(fileData.Data); 436 } 437 t->validatePropList(trim); 438 439 ts = t; 440 return errSecSuccess; 441 } 442 443 /* 444 * Create from external data, obtained by createExternal(). 445 * If externalData is NULL, we'll create an empty mTrustDict. 446 */ 447 OSStatus TrustSettings::CreateTrustSettings( 448 SecTrustSettingsDomain domain, 449 CFDataRef externalData, 450 TrustSettings*& ts) 451 { 452 switch(domain) { 453 case kSecTrustSettingsDomainUser: 454 case kSecTrustSettingsDomainAdmin: 455 case kSecTrustSettingsDomainMemory: 456 break; 457 case kSecTrustSettingsDomainSystem: /* no can do, that implies writing to it */ 458 default: 459 return errSecParam; 460 } 461 462 TrustSettings* t = new TrustSettings(domain); 463 464 if(externalData != NULL) { 465 t->initFromData(externalData); 466 } 467 else { 468 t->mPropList = tsInitialDict(); 469 } 470 t->validatePropList(TRIM_NO); /* never trim this */ 471 t->mDirty = true; 472 473 ts = t; 474 return errSecSuccess; 475 } 476 477 478 TrustSettings::~TrustSettings() 479 { 480 trustSettingsDbg("TrustSettings(domain %d) destructor", (int)mDomain); 481 CFRELEASE(mPropList); /* may be null if trimmed */ 482 CFRELEASE(mTrustDict); /* normally always non-NULL */ 483 484 } 485 486 /* common code to init mPropList from raw data */ 487 void TrustSettings::initFromData( 488 CFDataRef trustSettingsData) 489 { 490 CFStringRef errStr = NULL; 491 492 mPropList = (CFMutableDictionaryRef)CFPropertyListCreateFromXMLData( 493 NULL, 494 trustSettingsData, 495 kCFPropertyListMutableContainersAndLeaves, 496 &errStr); 497 if(mPropList == NULL) { 498 trustSettingsDbg("TrustSettings::initFromData decode err (%s)", 499 errStr ? CFStringGetCStringPtr(errStr, kCFStringEncodingUTF8) : "<no err>"); 500 if(errStr != NULL) { 501 CFRelease(errStr); 502 } 503 MacOSError::throwMe(errSecInvalidTrustSettings); 504 } 505 } 506 507 /* 508 * Flush property list data out to disk if dirty. 509 */ 510 void TrustSettings::flushToDisk() 511 { 512 if(!mDirty) { 513 trustSettingsDbg("flushToDisk, domain %d, !dirty!", (int)mDomain); 514 return; 515 } 516 if(mPropList == NULL) { 517 trustSettingsDbg("flushToDisk, domain %d, trimmed!", (int)mDomain); 518 assert(0); 519 MacOSError::throwMe(errSecInternalComponent); 520 } 521 switch(mDomain) { 522 case kSecTrustSettingsDomainSystem: 523 case kSecTrustSettingsDomainMemory: 524 /* caller shouldn't even try this */ 525 default: 526 trustSettingsDbg("flushToDisk, bad domain (%d)", (int)mDomain); 527 MacOSError::throwMe(errSecInternalComponent); 528 case kSecTrustSettingsDomainUser: 529 case kSecTrustSettingsDomainAdmin: 530 break; 531 } 532 533 /* 534 * Optimization: if there are no certs in the mTrustDict dictionary, 535 * we tell ocspd to *remove* the settings for the specified domain. 536 * Having *no* settings uses less memory and is faster than having 537 * an empty settings file, especially for the admin domain, where we 538 * can avoid 539 * an RPC if the settings file is simply not there. 540 */ 541 CFRef<CFDataRef> xmlData; 542 CSSM_DATA cssmXmlData = {0, NULL}; 543 CFIndex numCerts = CFDictionaryGetCount(mTrustDict); 544 if(numCerts) { 545 xmlData.take(CFPropertyListCreateXMLData(NULL, mPropList)); 546 if(!xmlData) { 547 /* we've been very careful; this should never happen */ 548 trustSettingsDbg("flushToDisk, domain %d: error converting to XML", (int)mDomain); 549 MacOSError::throwMe(errSecInternalComponent); 550 } 551 cssmXmlData.Data = (uint8 *)CFDataGetBytePtr(xmlData); 552 cssmXmlData.Length = CFDataGetLength(xmlData); 553 } 554 else { 555 trustSettingsDbg("flushToDisk, domain %d: DELETING trust settings", (int)mDomain); 556 } 557 558 /* cook up auth stuff so ocspd can act on our behalf */ 559 AuthorizationRef authRef; 560 OSStatus ortn; 561 ortn = AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment, 562 0, &authRef); 563 if(ortn) { 564 trustSettingsDbg("flushToDisk, domain %d: AuthorizationCreate returned %ld", 565 (int)mDomain, (long)ortn); 566 MacOSError::throwMe(errSecInternalComponent); 567 } 568 AuthorizationExternalForm authExt; 569 CSSM_DATA authBlob = {sizeof(authExt), (uint8 *)&authExt}; 570 ortn = AuthorizationMakeExternalForm(authRef, &authExt); 571 if(ortn) { 572 trustSettingsDbg("flushToDisk, domain %d: AuthorizationMakeExternalForm returned %ld", 573 (int)mDomain, (long)ortn); 574 ortn = errSecInternalComponent; 575 goto errOut; 576 } 577 578 ortn = ocspdTrustSettingsWrite(mDomain, authBlob, cssmXmlData); 579 if(ortn) { 580 trustSettingsDbg("flushToDisk, domain %d: ocspdTrustSettingsWrite returned %ld", 581 (int)mDomain, (long)ortn); 582 goto errOut; 583 } 584 trustSettingsDbg("flushToDisk, domain %d: wrote to disk", (int)mDomain); 585 mDirty = false; 586 errOut: 587 AuthorizationFree(authRef, 0); 588 if(ortn) { 589 MacOSError::throwMe(ortn); 590 } 591 } 592 593 /* 594 * Obtain external representation of TrustSettings data. 595 */ 596 CFDataRef TrustSettings::createExternal() 597 { 598 assert(mPropList); 599 CFDataRef xmlData = CFPropertyListCreateXMLData(NULL, mPropList); 600 if(xmlData == NULL) { 601 trustSettingsDbg("createExternal, domain %d: error converting to XML", 602 (int)mDomain); 603 MacOSError::throwMe(errSecInternalComponent); 604 } 605 return xmlData; 606 } 607 608 /* 609 * Evaluate specified cert. Returns true if we found a record for the cert 610 * matching specified constraints. 611 * Note that a true return with a value of kSecTrustSettingsResultUnspecified for 612 * the resultType means that a cert isn't to be trusted or untrusted 613 * per se; it just means that we only found allowedErrors entries. 614 * 615 * Found "allows errors" values are added to the incoming allowedErrors 616 * array which is reallocd as needed (and which may be NULL or non-NULL on 617 * entry). 618 */ 619 bool TrustSettings::evaluateCert( 620 CFStringRef certHashStr, 621 const CSSM_OID *policyOID, /* optional */ 622 const char *policyStr, /* optional */ 623 SecTrustSettingsKeyUsage keyUsage, /* optional */ 624 bool isRootCert, /* for checking default setting */ 625 CSSM_RETURN **allowedErrors, /* IN/OUT; reallocd as needed */ 626 uint32 *numAllowedErrors, /* IN/OUT */ 627 SecTrustSettingsResult *resultType, /* RETURNED */ 628 bool *foundAnyEntry) /* RETURNED */ 629 { 630 assert(mTrustDict != NULL); 631 632 /* get trust settings dictionary for this cert */ 633 CFDictionaryRef certDict = findDictionaryForCertHash(certHashStr); 634 #if CERT_HASH_DEBUG 635 /* @@@ debug only @@@ */ 636 /* print certificate hash and found dictionary reference */ 637 const size_t maxHashStrLen = 512; 638 char *buf = (char*)malloc(maxHashStrLen); 639 if (buf) { 640 if (!CFStringGetCString(certHashStr, buf, (CFIndex)maxHashStrLen, kCFStringEncodingUTF8)) { 641 buf[0]='\0'; 642 } 643 trustSettingsEvalDbg("evaluateCert for \"%s\", found dict %p", buf, certDict); 644 free(buf); 645 } 646 #endif 647 648 if(certDict == NULL) { 649 *foundAnyEntry = false; 650 return false; 651 } 652 *foundAnyEntry = true; 653 654 /* to-be-returned array of allowed errors */ 655 CSSM_RETURN *allowedErrs = *allowedErrors; 656 uint32 numAllowedErrs = *numAllowedErrors; 657 658 /* this means "we found something other than allowedErrors" if true */ 659 bool foundSettings = false; 660 661 /* to be returned in *resultType if it ends up something other than Invalid */ 662 SecTrustSettingsResult returnedResult = kSecTrustSettingsResultInvalid; 663 664 /* 665 * Note since we validated the entire mPropList in our constructor, and we're careful 666 * about what we put into it, we don't bother typechecking its contents here. 667 * Also note that the kTrustRecordTrustSettings entry is optional. 668 */ 669 CFArrayRef trustSettings = (CFArrayRef)CFDictionaryGetValue(certDict, 670 kTrustRecordTrustSettings); 671 CFIndex numSpecs = 0; 672 if(trustSettings != NULL) { 673 numSpecs = CFArrayGetCount(trustSettings); 674 } 675 if(numSpecs == 0) { 676 /* 677 * Trivial case: cert has no trust settings, indicating that 678 * it's used for everything. 679 */ 680 trustSettingsEvalDbg("evaluateCert: no trust settings"); 681 /* the default... */ 682 *resultType = kSecTrustSettingsResultTrustRoot; 683 return true; 684 } 685 686 /* 687 * The decidedly nontrivial part: grind thru all of the cert's trust 688 * settings, see if the cert matches the caller's specified usage. 689 */ 690 for(CFIndex addDex=0; addDex<numSpecs; addDex++) { 691 CFDictionaryRef tsDict = (CFDictionaryRef)CFArrayGetValueAtIndex(trustSettings, 692 addDex); 693 694 /* per-cert specs: all optional */ 695 CFDataRef certPolicy = (CFDataRef)CFDictionaryGetValue(tsDict, 696 kSecTrustSettingsPolicy); 697 CFDataRef certApp = (CFDataRef)CFDictionaryGetValue(tsDict, 698 kSecTrustSettingsApplication); 699 CFStringRef certPolicyStr = (CFStringRef)CFDictionaryGetValue(tsDict, 700 kSecTrustSettingsPolicyString); 701 CFNumberRef certKeyUsage = (CFNumberRef)CFDictionaryGetValue(tsDict, 702 kSecTrustSettingsKeyUsage); 703 CFNumberRef certResultType = (CFNumberRef)CFDictionaryGetValue(tsDict, 704 kSecTrustSettingsResult); 705 CFNumberRef certAllowedErr = (CFNumberRef)CFDictionaryGetValue(tsDict, 706 kSecTrustSettingsAllowedError); 707 708 /* now, skip if we find a constraint that doesn't match intended use */ 709 if(!tsCheckPolicy(policyOID, certPolicy)) { 710 continue; 711 } 712 if(!tsCheckApp(certApp)) { 713 continue; 714 } 715 if(!tsCheckKeyUse(keyUsage, certKeyUsage)) { 716 continue; 717 } 718 if(!tsCheckPolicyStr(policyStr, certPolicyStr)) { 719 continue; 720 } 721 722 trustSettingsEvalDbg("evaluateCert: MATCH"); 723 foundSettings = true; 724 725 if(certAllowedErr) { 726 /* note we already validated this value */ 727 SInt32 s; 728 CFNumberGetValue(certAllowedErr, kCFNumberSInt32Type, &s); 729 allowedErrs = (CSSM_RETURN *)::realloc(allowedErrs, 730 ++numAllowedErrs * sizeof(CSSM_RETURN)); 731 allowedErrs[numAllowedErrs-1] = (CSSM_RETURN) s; 732 } 733 734 /* 735 * We found a match, but we only return the current result type 736 * to caller if we haven't already returned something other than 737 * kSecTrustSettingsResultUnspecified. Once we find a valid result type, 738 * we keep on searching, but only for additional allowed errors. 739 */ 740 switch(returnedResult) { 741 /* found match but no valid resultType yet */ 742 case kSecTrustSettingsResultUnspecified: 743 /* haven't been thru here */ 744 case kSecTrustSettingsResultInvalid: 745 if(certResultType) { 746 /* note we already validated this */ 747 SInt32 s; 748 CFNumberGetValue(certResultType, kCFNumberSInt32Type, &s); 749 returnedResult = (SecTrustSettingsResult)s; 750 } 751 else { 752 /* default is "copacetic" */ 753 returnedResult = kSecTrustSettingsResultTrustRoot; 754 } 755 break; 756 default: 757 /* we already have a definitive resultType, don't change it */ 758 break; 759 } 760 } /* for each dictionary in trustSettings */ 761 762 *allowedErrors = allowedErrs; 763 *numAllowedErrors = numAllowedErrs; 764 if(returnedResult != kSecTrustSettingsResultInvalid) { 765 *resultType = returnedResult; 766 } 767 return foundSettings; 768 } 769 770 771 /* 772 * Find all certs in specified keychain list which have entries in this trust record. 773 * Certs already in the array are not added. 774 */ 775 void TrustSettings::findCerts( 776 StorageManager::KeychainList &keychains, 777 CFMutableArrayRef certArray) 778 { 779 findQualifiedCerts(keychains, 780 true, /* findAll */ 781 false, /* onlyRoots */ 782 NULL, NULL, kSecTrustSettingsKeyUseAny, 783 certArray); 784 } 785 786 void TrustSettings::findQualifiedCerts( 787 StorageManager::KeychainList &keychains, 788 /* 789 * If findAll is true, all certs are returned and the subsequent 790 * qualifiers are ignored 791 */ 792 bool findAll, 793 /* if true, only return root (self-signed) certs */ 794 bool onlyRoots, 795 const CSSM_OID *policyOID, /* optional */ 796 const char *policyString, /* optional */ 797 SecTrustSettingsKeyUsage keyUsage, /* optional */ 798 CFMutableArrayRef certArray) /* certs appended here */ 799 { 800 StLock<Mutex> _(SecTrustKeychainsGetMutex()); 801 802 /* 803 * a set, hopefully with a good hash function for CFData, to keep track of what's 804 * been added to the outgoing array. 805 */ 806 CFRef<CFMutableSetRef> certSet(CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks)); 807 808 /* search: all certs, no attributes */ 809 KCCursor cursor(keychains, (SecItemClass) CSSM_DL_DB_RECORD_X509_CERTIFICATE, NULL); 810 Item certItem; 811 bool found; 812 unsigned int total=0, entries=0, qualified=0; 813 do { 814 found = cursor->next(certItem); 815 if(!found) { 816 break; 817 } 818 ++total; 819 820 /* must convert to unified SecCertificateRef */ 821 SecPointer<Certificate> certificate(static_cast<Certificate *>(&*certItem)); 822 CssmData certCssmData; 823 try { 824 certCssmData = certificate->data(); 825 } 826 catch (...) {} 827 if (!(certCssmData.Data && certCssmData.Length)) { 828 continue; 829 } 830 CFRef<CFDataRef> cfDataRef(CFDataCreate(NULL, certCssmData.Data, certCssmData.Length)); 831 CFRef<SecCertificateRef> certRef(SecCertificateCreateWithData(NULL, cfDataRef)); 832 833 /* do we have an entry for this cert? */ 834 CFDictionaryRef certDict = findDictionaryForCert(certRef); 835 if(certDict == NULL) { 836 continue; 837 } 838 ++entries; 839 840 if(!findAll) { 841 /* qualify */ 842 if(!qualifyUsageWithCertDict(certDict, policyOID, 843 policyString, keyUsage, onlyRoots)) { 844 continue; 845 } 846 } 847 ++qualified; 848 849 /* see if we already have this one - get in CFData form */ 850 CSSM_DATA certData; 851 OSStatus ortn = SecCertificateGetData(certRef, &certData); 852 if(ortn) { 853 trustSettingsEvalDbg("findQualifiedCerts: SecCertificateGetData error"); 854 continue; 855 } 856 CFRef<CFDataRef> cfData(CFDataCreate(NULL, certData.Data, certData.Length)); 857 CFDataRef cfd = cfData.get(); 858 if(CFSetContainsValue(certSet, cfd)) { 859 trustSettingsEvalDbg("findQualifiedCerts: dup cert"); 860 continue; 861 } 862 else { 863 /* add to the tracking set, which owns the CFData now */ 864 CFSetAddValue(certSet, cfd); 865 /* and add the SecCert to caller's array, which owns that now */ 866 CFArrayAppendValue(certArray, certRef); 867 } 868 } while(found); 869 870 trustSettingsEvalDbg("findQualifiedCerts: examined %d certs, qualified %d of %d", 871 total, qualified, entries); 872 } 873 874 /* 875 * Obtain trust settings for the specified cert. Returned settings array 876 * is in the public API form; caller must release. Returns NULL 877 * (does not throw) if the cert is not present in this TrustRecord. 878 */ 879 CFArrayRef TrustSettings::copyTrustSettings( 880 SecCertificateRef certRef) 881 { 882 CFDictionaryRef certDict = NULL; 883 884 /* find the on-disk usage constraints for this cert */ 885 certDict = findDictionaryForCert(certRef); 886 if(certDict == NULL) { 887 trustSettingsDbg("copyTrustSettings: dictionary not found"); 888 return NULL; 889 } 890 CFArrayRef diskTrustSettings = (CFArrayRef)CFDictionaryGetValue(certDict, 891 kTrustRecordTrustSettings); 892 CFIndex numSpecs = 0; 893 if(diskTrustSettings != NULL) { 894 /* this field is optional */ 895 numSpecs = CFArrayGetCount(diskTrustSettings); 896 } 897 898 /* 899 * Convert to API-style array of dictionaries. 900 * We give the caller an array even if it's empty. 901 */ 902 CFRef<CFMutableArrayRef> outArray(CFArrayCreateMutable(NULL, numSpecs, 903 &kCFTypeArrayCallBacks)); 904 for(CFIndex dex=0; dex<numSpecs; dex++) { 905 CFDictionaryRef diskTsDict = 906 (CFDictionaryRef)CFArrayGetValueAtIndex(diskTrustSettings, dex); 907 /* already validated... */ 908 assert(CFGetTypeID(diskTsDict) == CFDictionaryGetTypeID()); 909 910 CFTypeRef certPolicy = (CFTypeRef) CFDictionaryGetValue(diskTsDict, kSecTrustSettingsPolicy); 911 CFStringRef policyName = (CFStringRef)CFDictionaryGetValue(diskTsDict, kSecTrustSettingsPolicyName); 912 CFDataRef certApp = (CFDataRef) CFDictionaryGetValue(diskTsDict, kSecTrustSettingsApplication); 913 CFStringRef policyStr = (CFStringRef)CFDictionaryGetValue(diskTsDict, kSecTrustSettingsPolicyString); 914 CFNumberRef allowedErr = (CFNumberRef)CFDictionaryGetValue(diskTsDict, kSecTrustSettingsAllowedError); 915 CFNumberRef resultType = (CFNumberRef)CFDictionaryGetValue(diskTsDict, kSecTrustSettingsResult); 916 CFNumberRef keyUsage = (CFNumberRef)CFDictionaryGetValue(diskTsDict, kSecTrustSettingsKeyUsage); 917 918 if((certPolicy == NULL) && 919 (certApp == NULL) && 920 (policyStr == NULL) && 921 (allowedErr == NULL) && 922 (resultType == NULL) && 923 (keyUsage == NULL)) { 924 /* weird but legal */ 925 continue; 926 } 927 CFRef<CFMutableDictionaryRef> outTsDict(CFDictionaryCreateMutable(NULL, 928 0, // capacity 929 &kCFTypeDictionaryKeyCallBacks, 930 &kCFTypeDictionaryValueCallBacks)); 931 932 if(certPolicy != NULL) { 933 SecPolicyRef policyRef = NULL; 934 if (CFDataGetTypeID() == CFGetTypeID(certPolicy)) { 935 /* convert OID as CFDataRef to SecPolicyRef */ 936 CSSM_OID policyOid = { int_cast<CFIndex, CSSM_SIZE>(CFDataGetLength((CFDataRef)certPolicy)), 937 (uint8 *)CFDataGetBytePtr((CFDataRef)certPolicy) }; 938 OSStatus ortn = SecPolicyCopy(CSSM_CERT_X_509v3, &policyOid, &policyRef); 939 if(ortn) { 940 trustSettingsDbg("copyTrustSettings: OID conversion error"); 941 abort("Bad Policy OID in trusted root list", errSecInvalidTrustedRootRecord); 942 } 943 } else if (CFStringGetTypeID() == CFGetTypeID(certPolicy)) { 944 policyRef = SecPolicyCreateWithProperties(certPolicy, NULL); 945 } 946 if (policyRef) { 947 CFDictionaryAddValue(outTsDict, kSecTrustSettingsPolicy, policyRef); 948 CFRelease(policyRef); // owned by dictionary 949 } 950 } 951 952 if (policyName != NULL) { 953 /* 954 * copy, since policyName is in our mutable dictionary and could change out from 955 * under the caller 956 */ 957 CFStringRef str = CFStringCreateCopy(NULL, policyName); 958 CFDictionaryAddValue(outTsDict, kSecTrustSettingsPolicyName, str); 959 CFRelease(str); // owned by dictionary 960 } 961 962 if(certApp != NULL) { 963 /* convert app as CFDataRef to SecTrustedApplicationRef */ 964 SecTrustedApplicationRef appRef; 965 OSStatus ortn = SecTrustedApplicationCreateWithExternalRepresentation(certApp, &appRef); 966 if(ortn) { 967 trustSettingsDbg("copyTrustSettings: App conversion error"); 968 abort("Bad application data in trusted root list", errSecInvalidTrustedRootRecord); 969 } 970 CFDictionaryAddValue(outTsDict, kSecTrustSettingsApplication, appRef); 971 CFRelease(appRef); // owned by dictionary 972 } 973 974 /* remaining 4 are trivial */ 975 if(policyStr != NULL) { 976 /* 977 * copy, since policyStr is in our mutable dictionary and could change out from 978 * under the caller 979 */ 980 CFStringRef str = CFStringCreateCopy(NULL, policyStr); 981 CFDictionaryAddValue(outTsDict, kSecTrustSettingsPolicyString, str); 982 CFRelease(str); // owned by dictionary 983 } 984 if(allowedErr != NULL) { 985 /* there is no mutable CFNumber, so.... */ 986 CFDictionaryAddValue(outTsDict, kSecTrustSettingsAllowedError, allowedErr); 987 } 988 if(resultType != NULL) { 989 CFDictionaryAddValue(outTsDict, kSecTrustSettingsResult, resultType); 990 } 991 if(keyUsage != NULL) { 992 CFDictionaryAddValue(outTsDict, kSecTrustSettingsKeyUsage, keyUsage); 993 } 994 CFArrayAppendValue(outArray, outTsDict); 995 /* outTsDict autoreleases; owned by outArray now */ 996 } 997 CFRetain(outArray); // now that it's good to go.... 998 return outArray; 999 } 1000 1001 CFDateRef TrustSettings::copyModDate( 1002 SecCertificateRef certRef) 1003 { 1004 CFDictionaryRef certDict = NULL; 1005 1006 /* find the on-disk usage constraints dictionary for this cert */ 1007 certDict = findDictionaryForCert(certRef); 1008 if(certDict == NULL) { 1009 trustSettingsDbg("copyModDate: dictionary not found"); 1010 return NULL; 1011 } 1012 CFDateRef modDate = (CFDateRef)CFDictionaryGetValue(certDict, kTrustRecordModDate); 1013 if(modDate == NULL) { 1014 return NULL; 1015 } 1016 1017 /* this only works becuase there is no mutable CFDateRef */ 1018 CFRetain(modDate); 1019 return modDate; 1020 } 1021 1022 bool TrustSettings::contains(SecCertificateRef certRef) 1023 { 1024 if(findDictionaryForCert(certRef) != NULL) { 1025 return true; 1026 } 1027 return false; 1028 } 1029 1030 /* 1031 * Modify cert's trust settings, or add a new cert to the record. 1032 */ 1033 void TrustSettings::setTrustSettings( 1034 SecCertificateRef certRef, 1035 CFTypeRef trustSettingsDictOrArray) 1036 { 1037 /* to validate, we need to know if the cert is self-signed */ 1038 OSStatus ortn; 1039 Boolean isSelfSigned = false; 1040 1041 if(certRef == kSecTrustSettingsDefaultRootCertSetting) { 1042 /* 1043 * Validate settings as if this were root, specifically, 1044 * kSecTrustSettingsResultTrustRoot (explicitly or by 1045 * default) is OK. 1046 */ 1047 isSelfSigned = true; 1048 } 1049 else { 1050 ortn = SecCertificateIsSelfSigned(certRef, &isSelfSigned); 1051 if(ortn) { 1052 MacOSError::throwMe(ortn); 1053 } 1054 } 1055 1056 /* caller's app/policy spec OK? */ 1057 CFRef<CFArrayRef> trustSettings(validateApiTrustSettings( 1058 trustSettingsDictOrArray, isSelfSigned)); 1059 1060 /* caller is responsible for ensuring these */ 1061 assert(mPropList != NULL); 1062 assert(mDomain != kSecTrustSettingsDomainSystem); 1063 1064 /* extract issuer and serial number from the cert, if it's a cert */ 1065 CFRef<CFDataRef> issuer; 1066 CFRef<CFDataRef> serial; 1067 if(certRef != kSecTrustSettingsDefaultRootCertSetting) { 1068 copyIssuerAndSerial(certRef, issuer.take(), serial.take()); 1069 } 1070 else { 1071 UInt8 dummy; 1072 issuer = CFDataCreate(NULL, &dummy, 0); 1073 serial = CFDataCreate(NULL, &dummy, 0); 1074 } 1075 1076 /* SHA1 digest as string */ 1077 CFRef<CFStringRef> certHashStr(SecTrustSettingsCertHashStrFromCert(certRef)); 1078 if(!certHashStr) { 1079 trustSettingsDbg("TrustSettings::setTrustSettings: CertHashStrFromCert error"); 1080 MacOSError::throwMe(errSecItemNotFound); 1081 } 1082 1083 /* 1084 * Find entry for this cert, if present. 1085 */ 1086 CFMutableDictionaryRef certDict = 1087 (CFMutableDictionaryRef)findDictionaryForCertHash(certHashStr); 1088 if(certDict == NULL) { 1089 /* create new dictionary */ 1090 certDict = CFDictionaryCreateMutable(NULL, kSecTrustRecordNumCertDictKeys, 1091 &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks); 1092 if(certDict == NULL) { 1093 MacOSError::throwMe(errSecAllocate); 1094 } 1095 CFDictionaryAddValue(certDict, kTrustRecordIssuer, issuer); 1096 CFDictionaryAddValue(certDict, kTrustRecordSerialNumber, serial); 1097 if(CFArrayGetCount(trustSettings) != 0) { 1098 /* skip this if the settings array is empty */ 1099 CFDictionaryAddValue(certDict, kTrustRecordTrustSettings, trustSettings); 1100 } 1101 tsSetModDate(certDict); 1102 1103 /* add this new cert dictionary to top-level mTrustDict */ 1104 CFDictionaryAddValue(mTrustDict, static_cast<CFStringRef>(certHashStr), certDict); 1105 1106 /* mTrustDict owns the dictionary now */ 1107 CFRelease(certDict); 1108 } 1109 else { 1110 /* update */ 1111 tsSetModDate(certDict); 1112 if(CFArrayGetCount(trustSettings) != 0) { 1113 CFDictionarySetValue(certDict, kTrustRecordTrustSettings, trustSettings); 1114 } 1115 else { 1116 /* empty settings array: remove from dictionary */ 1117 CFDictionaryRemoveValue(certDict, kTrustRecordTrustSettings); 1118 } 1119 } 1120 mDirty = true; 1121 } 1122 1123 /* 1124 * Delete a certificate's trust settings. 1125 */ 1126 void TrustSettings::deleteTrustSettings( 1127 SecCertificateRef certRef) 1128 { 1129 CFDictionaryRef certDict = NULL; 1130 1131 /* caller is responsible for ensuring these */ 1132 assert(mPropList != NULL); 1133 assert(mDomain != kSecTrustSettingsDomainSystem); 1134 1135 /* SHA1 digest as string */ 1136 CFRef<CFStringRef> certHashStr(SecTrustSettingsCertHashStrFromCert(certRef)); 1137 if(!certHashStr) { 1138 MacOSError::throwMe(errSecItemNotFound); 1139 } 1140 1141 /* present in top-level mTrustDict? */ 1142 certDict = findDictionaryForCertHash(certHashStr); 1143 if(certDict != NULL) { 1144 CFDictionaryRemoveValue(mTrustDict, static_cast<CFStringRef>(certHashStr)); 1145 mDirty = true; 1146 } 1147 else { 1148 /* 1149 * Throwing this error is the only reason we don't blindly do 1150 * a CFDictionaryRemoveValue() without first doing 1151 * findDictionaryForCertHash(). 1152 */ 1153 trustSettingsDbg("TrustSettings::deleteRoot: cert dictionary not found"); 1154 MacOSError::throwMe(errSecItemNotFound); 1155 } 1156 } 1157 1158 #pragma mark --- Private methods --- 1159 1160 /* 1161 * Find a given cert's entry in the top-level mTrustDict. Return the 1162 * entry as a dictionary. Returned dictionary is not refcounted. 1163 * The mutability of the returned dictionary is the same as the mutability 1164 * of the underlying StickRecord::mPropList, which the caller is just 1165 * going to have to know (and cast accordingly if a mutable dictionary 1166 * is needed). 1167 */ 1168 CFDictionaryRef TrustSettings::findDictionaryForCert( 1169 SecCertificateRef certRef) 1170 { 1171 CFRef<CFStringRef> certHashStr(SecTrustSettingsCertHashStrFromCert(certRef)); 1172 if (certHashStr.get() == NULL) 1173 { 1174 return NULL; 1175 } 1176 1177 return findDictionaryForCertHash(static_cast<CFStringRef>(certHashStr.get())); 1178 } 1179 1180 /* 1181 * Find entry in mTrustDict given cert hash string. 1182 */ 1183 CFDictionaryRef TrustSettings::findDictionaryForCertHash( 1184 CFStringRef certHashStr) 1185 { 1186 assert(mTrustDict != NULL); 1187 return (CFDictionaryRef)CFDictionaryGetValue(mTrustDict, certHashStr); 1188 } 1189 1190 /* 1191 * Validate incoming trust settings, which may be NULL, a dictionary, or 1192 * an array of dictionaries. Convert from the API-style dictionaries 1193 * to the internal style suitable for writing to disk as part of 1194 * mPropList. 1195 * 1196 * We return a refcounted CFArray in any case if the incoming parameter is good. 1197 */ 1198 CFArrayRef TrustSettings::validateApiTrustSettings( 1199 CFTypeRef trustSettingsDictOrArray, 1200 Boolean isSelfSigned) 1201 { 1202 CFArrayRef tmpInArray = NULL; 1203 1204 if(trustSettingsDictOrArray == NULL) { 1205 /* trivial case, only valid for roots */ 1206 if(!isSelfSigned) { 1207 trustSettingsDbg("validateApiUsageConstraints: !isSelfSigned, no settings"); 1208 MacOSError::throwMe(errSecParam); 1209 } 1210 return CFArrayCreate(NULL, NULL, 0, &kCFTypeArrayCallBacks); 1211 } 1212 else if(CFGetTypeID(trustSettingsDictOrArray) == CFDictionaryGetTypeID()) { 1213 /* array-ize it */ 1214 tmpInArray = CFArrayCreate(NULL, &trustSettingsDictOrArray, 1, 1215 &kCFTypeArrayCallBacks); 1216 } 1217 else if(CFGetTypeID(trustSettingsDictOrArray) == CFArrayGetTypeID()) { 1218 /* as is, refcount - we'll release later */ 1219 tmpInArray = (CFArrayRef)trustSettingsDictOrArray; 1220 CFRetain(tmpInArray); 1221 } 1222 else { 1223 trustSettingsDbg("validateApiUsageConstraints: bad trustSettingsDictOrArray"); 1224 MacOSError::throwMe(errSecParam); 1225 } 1226 1227 CFIndex numSpecs = CFArrayGetCount(tmpInArray); 1228 CFMutableArrayRef outArray = CFArrayCreateMutable(NULL, numSpecs, &kCFTypeArrayCallBacks); 1229 CSSM_OID oid; 1230 OSStatus ortn = errSecSuccess; 1231 SecPolicyRef certPolicy; 1232 SecTrustedApplicationRef certApp; 1233 CFTypeRef oidData = NULL; 1234 1235 /* convert */ 1236 for(CFIndex dex=0; dex<numSpecs; dex++) { 1237 CFStringRef policyName = NULL; 1238 CFDataRef appData = NULL; 1239 CFStringRef policyStr = NULL; 1240 CFNumberRef allowedErr = NULL; 1241 CFNumberRef resultType = NULL; 1242 CFNumberRef keyUsage = NULL; 1243 SInt32 resultNum; 1244 SecTrustSettingsResult result; 1245 1246 /* each element is a dictionary */ 1247 CFDictionaryRef ucDict = (CFDictionaryRef)CFArrayGetValueAtIndex(tmpInArray, dex); 1248 if(CFGetTypeID(ucDict) != CFDictionaryGetTypeID()) { 1249 trustSettingsDbg("validateAppPolicyArray: malformed usageConstraint dictionary"); 1250 ortn = errSecParam; 1251 break; 1252 } 1253 1254 /* policy - optional */ 1255 certPolicy = (SecPolicyRef)CFDictionaryGetValue(ucDict, kSecTrustSettingsPolicy); 1256 if(certPolicy != NULL) { 1257 if(CFGetTypeID(certPolicy) != SecPolicyGetTypeID()) { 1258 trustSettingsDbg("validateAppPolicyArray: malformed certPolicy"); 1259 ortn = errSecParam; 1260 break; 1261 } 1262 ortn = SecPolicyGetOID(certPolicy, &oid); 1263 if (ortn) { 1264 /* newer policies don't have CSSM OIDs but they do have string OIDs */ 1265 oidData = CFRetain(SecPolicyGetOidString(certPolicy)); 1266 } else { 1267 oidData = CFDataCreate(NULL, oid.Data, oid.Length); 1268 } 1269 1270 if (!oidData) { 1271 trustSettingsDbg("validateAppPolicyArray: SecPolicyGetOID error"); 1272 break; 1273 } 1274 policyName = SecPolicyGetName(certPolicy); 1275 } 1276 1277 /* application - optional */ 1278 certApp = (SecTrustedApplicationRef)CFDictionaryGetValue(ucDict, kSecTrustSettingsApplication); 1279 if(certApp != NULL) { 1280 if(CFGetTypeID(certApp) != SecTrustedApplicationGetTypeID()) { 1281 trustSettingsDbg("validateAppPolicyArray: malformed certApp"); 1282 ortn = errSecParam; 1283 break; 1284 } 1285 ortn = SecTrustedApplicationCopyExternalRepresentation(certApp, &appData); 1286 if(ortn) { 1287 trustSettingsDbg("validateAppPolicyArray: " 1288 "SecTrustedApplicationCopyExternalRepresentation error"); 1289 break; 1290 } 1291 } 1292 1293 policyStr = (CFStringRef)CFDictionaryGetValue(ucDict, kSecTrustSettingsPolicyString); 1294 if(policyStr != NULL) { 1295 if(CFGetTypeID(policyStr) != CFStringGetTypeID()) { 1296 trustSettingsDbg("validateAppPolicyArray: malformed policyStr"); 1297 ortn = errSecParam; 1298 break; 1299 } 1300 } 1301 allowedErr = (CFNumberRef)CFDictionaryGetValue(ucDict, kSecTrustSettingsAllowedError); 1302 if(!tsIsGoodCfNum(allowedErr)) { 1303 trustSettingsDbg("validateAppPolicyArray: malformed allowedErr"); 1304 ortn = errSecParam; 1305 break; 1306 } 1307 resultType = (CFNumberRef)CFDictionaryGetValue(ucDict, kSecTrustSettingsResult); 1308 if(!tsIsGoodCfNum(resultType, &resultNum)) { 1309 trustSettingsDbg("validateAppPolicyArray: malformed resultType"); 1310 ortn = errSecParam; 1311 break; 1312 } 1313 result = (SecTrustSettingsResult) resultNum; 1314 /* validate result later */ 1315 1316 keyUsage = (CFNumberRef)CFDictionaryGetValue(ucDict, kSecTrustSettingsKeyUsage); 1317 if(!tsIsGoodCfNum(keyUsage)) { 1318 trustSettingsDbg("validateAppPolicyArray: malformed keyUsage"); 1319 ortn = errSecParam; 1320 break; 1321 } 1322 1323 if(!oidData && !appData && !policyStr && 1324 !allowedErr && !resultType && !keyUsage) { 1325 /* nothing here - weird, but legal - skip it */ 1326 continue; 1327 } 1328 1329 /* create dictionary for this usageConstraint */ 1330 CFMutableDictionaryRef outDict = CFDictionaryCreateMutable(NULL, 1331 2, 1332 &kCFTypeDictionaryKeyCallBacks, 1333 &kCFTypeDictionaryValueCallBacks); 1334 if(oidData) { 1335 CFDictionaryAddValue(outDict, kSecTrustSettingsPolicy, oidData); 1336 CFReleaseNull(oidData); // owned by dictionary 1337 } 1338 if(policyName) { 1339 CFDictionaryAddValue(outDict, kSecTrustSettingsPolicyName, policyName); 1340 /* still owned by ucDict */ 1341 } 1342 if(appData) { 1343 CFDictionaryAddValue(outDict, kSecTrustSettingsApplication, appData); 1344 CFRelease(appData); // owned by dictionary 1345 } 1346 if(policyStr) { 1347 CFDictionaryAddValue(outDict, kSecTrustSettingsPolicyString, policyStr); 1348 /* still owned by ucDict */ 1349 } 1350 if(allowedErr) { 1351 CFDictionaryAddValue(outDict, kSecTrustSettingsAllowedError, allowedErr); 1352 } 1353 1354 ortn = errSecSuccess; 1355 1356 if(resultType) { 1357 /* let's be really picky on this one */ 1358 switch(result) { 1359 case kSecTrustSettingsResultInvalid: 1360 ortn = errSecParam; 1361 break; 1362 case kSecTrustSettingsResultTrustRoot: 1363 if(!isSelfSigned) { 1364 trustSettingsDbg("validateAppPolicyArray: TrustRoot, !isSelfSigned"); 1365 ortn = errSecParam; 1366 } 1367 break; 1368 case kSecTrustSettingsResultTrustAsRoot: 1369 if(isSelfSigned) { 1370 trustSettingsDbg("validateAppPolicyArray: TrustAsRoot, isSelfSigned"); 1371 ortn = errSecParam; 1372 } 1373 break; 1374 case kSecTrustSettingsResultDeny: 1375 case kSecTrustSettingsResultUnspecified: 1376 break; 1377 default: 1378 trustSettingsDbg("validateAppPolicyArray: bogus resultType"); 1379 ortn = errSecParam; 1380 break; 1381 } 1382 if(ortn) { 1383 break; 1384 } 1385 CFDictionaryAddValue(outDict, kSecTrustSettingsResult, resultType); 1386 } 1387 else { 1388 /* no resultType; default of TrustRoot only valid for root */ 1389 if(!isSelfSigned) { 1390 trustSettingsDbg("validateAppPolicyArray: default result, !isSelfSigned"); 1391 ortn = errSecParam; 1392 break; 1393 } 1394 } 1395 1396 if(keyUsage) { 1397 CFDictionaryAddValue(outDict, kSecTrustSettingsKeyUsage, keyUsage); 1398 } 1399 1400 /* append dictionary to output */ 1401 CFArrayAppendValue(outArray, outDict); 1402 /* array owns the dictionary now */ 1403 CFRelease(outDict); 1404 1405 } /* for each usage constraint dictionary */ 1406 1407 CFReleaseNull(oidData); 1408 CFRelease(tmpInArray); 1409 if(ortn) { 1410 CFRelease(outArray); 1411 MacOSError::throwMe(ortn); 1412 } 1413 return outArray; 1414 } 1415 1416 /* 1417 * Validate an trust settings array obtained from disk. 1418 * Returns true if OK, else returns false. 1419 */ 1420 bool TrustSettings::validateTrustSettingsArray( 1421 CFArrayRef trustSettings) 1422 { 1423 CFIndex numSpecs = CFArrayGetCount(trustSettings); 1424 for(CFIndex dex=0; dex<numSpecs; dex++) { 1425 CFDictionaryRef ucDict = (CFDictionaryRef)CFArrayGetValueAtIndex(trustSettings, 1426 dex); 1427 if(CFGetTypeID(ucDict) != CFDictionaryGetTypeID()) { 1428 trustSettingsDbg("validateAppPolicyArray: malformed app/policy dictionary"); 1429 return false; 1430 } 1431 CFDataRef certPolicy = (CFDataRef)CFDictionaryGetValue(ucDict, kSecTrustSettingsPolicy); 1432 if((certPolicy != NULL) && (CFGetTypeID(certPolicy) != CFDataGetTypeID())) { 1433 trustSettingsDbg("validateAppPolicyArray: malformed certPolicy"); 1434 return false; 1435 } 1436 CFDataRef certApp = (CFDataRef)CFDictionaryGetValue(ucDict, kSecTrustSettingsApplication); 1437 if((certApp != NULL) && (CFGetTypeID(certApp) != CFDataGetTypeID())) { 1438 trustSettingsDbg("validateAppPolicyArray: malformed certApp"); 1439 return false; 1440 } 1441 CFStringRef policyStr = (CFStringRef)CFDictionaryGetValue(ucDict, kSecTrustSettingsPolicyString); 1442 if((policyStr != NULL) && (CFGetTypeID(policyStr) != CFStringGetTypeID())) { 1443 trustSettingsDbg("validateAppPolicyArray: malformed policyStr"); 1444 return false; 1445 } 1446 CFNumberRef cfNum = (CFNumberRef)CFDictionaryGetValue(ucDict, kSecTrustSettingsAllowedError); 1447 if(!tsIsGoodCfNum(cfNum)) { 1448 trustSettingsDbg("validateAppPolicyArray: malformed allowedErr"); 1449 return false; 1450 } 1451 cfNum = (CFNumberRef)CFDictionaryGetValue(ucDict, kSecTrustSettingsResult); 1452 if(!tsIsGoodCfNum(cfNum)) { 1453 trustSettingsDbg("validateAppPolicyArray: malformed resultType"); 1454 return false; 1455 } 1456 cfNum = (CFNumberRef)CFDictionaryGetValue(ucDict, kSecTrustSettingsKeyUsage); 1457 if(!tsIsGoodCfNum(cfNum)) { 1458 trustSettingsDbg("validateAppPolicyArray: malformed keyUsage"); 1459 return false; 1460 } 1461 } /* for each usageConstraint dictionary */ 1462 return true; 1463 } 1464 1465 /* 1466 * Validate mPropList after it's read from disk or supplied as an external 1467 * representation. Allows subsequent use of mTrustDict to proceed with 1468 * relative impunity. 1469 */ 1470 void TrustSettings::validatePropList(bool trim) 1471 { 1472 /* top level dictionary */ 1473 if(!mPropList) { 1474 trustSettingsDbg("TrustSettings::validatePropList missing mPropList"); 1475 abort("missing propList", errSecInvalidTrustedRootRecord); 1476 } 1477 1478 if(CFGetTypeID(mPropList) != CFDictionaryGetTypeID()) { 1479 trustSettingsDbg("TrustSettings::validatePropList: malformed mPropList"); 1480 abort("malformed propList", errSecInvalidTrustedRootRecord); 1481 } 1482 1483 /* That dictionary has two entries */ 1484 CFNumberRef cfVers = (CFNumberRef)CFDictionaryGetValue(mPropList, kTrustRecordVersion); 1485 if((cfVers == NULL) || (CFGetTypeID(cfVers) != CFNumberGetTypeID())) { 1486 trustSettingsDbg("TrustSettings::validatePropList: malformed version"); 1487 abort("malformed version", errSecInvalidTrustedRootRecord); 1488 } 1489 if(!CFNumberGetValue(cfVers, kCFNumberSInt32Type, &mDictVersion)) { 1490 trustSettingsDbg("TrustSettings::validatePropList: malformed version"); 1491 abort("malformed version", errSecInvalidTrustedRootRecord); 1492 } 1493 if((mDictVersion > kSecTrustRecordVersionCurrent) || 1494 (mDictVersion == kSecTrustRecordVersionInvalid)) { 1495 trustSettingsDbg("TrustSettings::validatePropList: incompatible version"); 1496 abort("incompatible version", errSecInvalidTrustedRootRecord); 1497 } 1498 /* other backwards-compatibility handling done later, if needed, per mDictVersion */ 1499 1500 mTrustDict = (CFMutableDictionaryRef)CFDictionaryGetValue(mPropList, kTrustRecordTrustList); 1501 if(mTrustDict != NULL) { 1502 CFRetain(mTrustDict); 1503 } 1504 if((mTrustDict == NULL) || (CFGetTypeID(mTrustDict) != CFDictionaryGetTypeID())) { 1505 trustSettingsDbg("TrustSettings::validatePropList: malformed mTrustDict"); 1506 abort("malformed TrustArray", errSecInvalidTrustedRootRecord); 1507 } 1508 1509 /* grind through the per-cert entries */ 1510 CFIndex numCerts = CFDictionaryGetCount(mTrustDict); 1511 const void *dictKeys[numCerts]; 1512 const void *dictValues[numCerts]; 1513 CFDictionaryGetKeysAndValues(mTrustDict, dictKeys, dictValues); 1514 1515 for(CFIndex dex=0; dex<numCerts; dex++) { 1516 /* get per-cert dictionary */ 1517 CFMutableDictionaryRef certDict = (CFMutableDictionaryRef)dictValues[dex]; 1518 if((certDict == NULL) || (CFGetTypeID(certDict) != CFDictionaryGetTypeID())) { 1519 trustSettingsDbg("TrustSettings::validatePropList: malformed certDict"); 1520 abort("malformed certDict", errSecInvalidTrustedRootRecord); 1521 } 1522 1523 /* 1524 * That dictionary has exactly four entries. 1525 * If we're trimming, all we need is the actual trust settings. 1526 */ 1527 1528 /* issuer */ 1529 CFDataRef cfd = (CFDataRef)CFDictionaryGetValue(certDict, kTrustRecordIssuer); 1530 if(cfd == NULL) { 1531 trustSettingsDbg("TrustSettings::validatePropList: missing issuer"); 1532 abort("missing issuer", errSecInvalidTrustedRootRecord); 1533 } 1534 if(CFGetTypeID(cfd) != CFDataGetTypeID()) { 1535 trustSettingsDbg("TrustSettings::validatePropList: malformed issuer"); 1536 abort("malformed issuer", errSecInvalidTrustedRootRecord); 1537 } 1538 if(trim) { 1539 CFDictionaryRemoveValue(certDict, kTrustRecordIssuer); 1540 } 1541 1542 /* serial number */ 1543 cfd = (CFDataRef)CFDictionaryGetValue(certDict, kTrustRecordSerialNumber); 1544 if(cfd == NULL) { 1545 trustSettingsDbg("TrustSettings::validatePropList: missing serial number"); 1546 abort("missing serial number", errSecInvalidTrustedRootRecord); 1547 } 1548 if(CFGetTypeID(cfd) != CFDataGetTypeID()) { 1549 trustSettingsDbg("TrustSettings::validatePropList: malformed serial number"); 1550 abort("malformed serial number", errSecInvalidTrustedRootRecord); 1551 } 1552 if(trim) { 1553 CFDictionaryRemoveValue(certDict, kTrustRecordSerialNumber); 1554 } 1555 1556 /* modification date */ 1557 CFDateRef modDate = (CFDateRef)CFDictionaryGetValue(certDict, kTrustRecordModDate); 1558 if(modDate == NULL) { 1559 trustSettingsDbg("TrustSettings::validatePropList: missing modDate"); 1560 abort("missing modDate", errSecInvalidTrustedRootRecord); 1561 } 1562 if(CFGetTypeID(modDate) != CFDateGetTypeID()) { 1563 trustSettingsDbg("TrustSettings::validatePropList: malformed modDate"); 1564 abort("malformed modDate", errSecInvalidTrustedRootRecord); 1565 } 1566 if(trim) { 1567 CFDictionaryRemoveValue(certDict, kTrustRecordModDate); 1568 } 1569 1570 /* the actual trust settings */ 1571 CFArrayRef trustSettings = (CFArrayRef)CFDictionaryGetValue(certDict, 1572 kTrustRecordTrustSettings); 1573 if(trustSettings == NULL) { 1574 /* optional; this cert's entry is good */ 1575 continue; 1576 } 1577 if(CFGetTypeID(trustSettings) != CFArrayGetTypeID()) { 1578 trustSettingsDbg("TrustSettings::validatePropList: malformed useConstraint" 1579 "array"); 1580 abort("malformed useConstraint array", errSecInvalidTrustedRootRecord); 1581 } 1582 1583 /* Now validate the usageConstraint array contents */ 1584 if(!validateTrustSettingsArray(trustSettings)) { 1585 abort("malformed useConstraint array", errSecInvalidTrustedRootRecord); 1586 } 1587 } /* for each cert dictionary in top-level array */ 1588 1589 if(trim) { 1590 /* we don't need the top-level dictionary any more */ 1591 CFRelease(mPropList); 1592 mPropList = NULL; 1593 } 1594 } 1595 1596 /* 1597 * Obtain non-normalized issuer and serial number for specified cert, both 1598 * returned as CFDataRefs owned by caller. 1599 */ 1600 void TrustSettings::copyIssuerAndSerial( 1601 SecCertificateRef certRef, 1602 CFDataRef *issuer, /* optional, RETURNED */ 1603 CFDataRef *serial) /* RETURNED */ 1604 { 1605 CFRef<SecCertificateRef> certificate = SecCertificateCreateItemImplInstance(certRef); 1606 1607 SecPointer<Certificate> cert = Certificate::required(certificate); 1608 CSSM_DATA_PTR fieldVal; 1609 1610 if(issuer != NULL) { 1611 fieldVal = cert->copyFirstFieldValue(CSSMOID_X509V1IssuerNameStd); 1612 *issuer = CFDataCreate(NULL, fieldVal->Data, fieldVal->Length); 1613 cert->releaseFieldValue(CSSMOID_X509V1IssuerNameStd, fieldVal); 1614 } 1615 1616 fieldVal = cert->copyFirstFieldValue(CSSMOID_X509V1SerialNumber); 1617 *serial = CFDataCreate(NULL, fieldVal->Data, fieldVal->Length); 1618 cert->releaseFieldValue(CSSMOID_X509V1SerialNumber, fieldVal); 1619 } 1620 1621 void TrustSettings::abort( 1622 const char *why, 1623 OSStatus err) 1624 { 1625 Syslog::error("TrustSettings: %s", why); 1626 MacOSError::throwMe(err); 1627 } 1628