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