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