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