]> git.saurik.com Git - apple/security.git/blame - OSX/libsecurity_keychain/lib/TrustSettings.cpp
Security-59754.80.3.tar.gz
[apple/security.git] / OSX / libsecurity_keychain / lib / TrustSettings.cpp
CommitLineData
b1ab9ed8 1/*
5c19dc3a
A
2 * Copyright (c) 2005,2011-2015 Apple Inc. All Rights Reserved.
3 *
b1ab9ed8 4 * @APPLE_LICENSE_HEADER_START@
5c19dc3a 5 *
b1ab9ed8
A
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.
5c19dc3a 12 *
b1ab9ed8
A
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.
5c19dc3a 20 *
b1ab9ed8
A
21 * @APPLE_LICENSE_HEADER_END@
22 */
23
24/*
5c19dc3a 25 * TrustSettings.h - class to manage cert trust settings.
b1ab9ed8 26 *
b1ab9ed8
A
27 */
28
29#include "TrustSettings.h"
30#include "TrustSettingsSchema.h"
b54c578e 31#include <Security/SecTrustSettings.h>
b1ab9ed8
A
32#include "TrustSettingsUtils.h"
33#include "TrustKeychains.h"
b1ab9ed8
A
34#include "Certificate.h"
35#include "cssmdatetime.h"
427c49bc 36#include <Security/SecBase.h>
b1ab9ed8 37#include "SecTrustedApplicationPriv.h"
5c19dc3a 38#include <security_utilities/errors.h>
b1ab9ed8
A
39#include <security_utilities/debugging.h>
40#include <security_utilities/logging.h>
41#include <security_utilities/cfutilities.h>
42#include <security_utilities/alloc.h>
6b200bc3
A
43#include <security_utilities/casts.h>
44#include <utilities/SecCFRelease.h>
fa7225c8 45#include <Security/Authorization.h>
b1ab9ed8
A
46#include <Security/cssmapplePriv.h>
47#include <Security/oidscert.h>
5c19dc3a
A
48#include <Security/SecCertificatePriv.h>
49#include <Security/SecPolicyPriv.h>
b1ab9ed8
A
50#include <security_keychain/KCCursor.h>
51#include <security_ocspd/ocspdClient.h>
52#include <CoreFoundation/CoreFoundation.h>
d64be36e 53#include <security_utilities/simulatecrash_assert.h>
fa7225c8 54#include <dispatch/dispatch.h>
b1ab9ed8 55#include <sys/stat.h>
fa7225c8 56#include <syslog.h>
b1ab9ed8 57
fa7225c8
A
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
b1ab9ed8 65
5c19dc3a 66/*
b1ab9ed8
A
67 * Common error return for "malformed TrustSettings record"
68 */
69#define errSecInvalidTrustedRootRecord errSecInvalidTrustSettings
70
71using namespace KeychainCore;
72
73#pragma mark --- Static functions ---
74
5c19dc3a 75/*
b1ab9ed8
A
76 * Comparator atoms to determine if an app's specified usage
77 * matches an individual trust setting. Each returns true on a match, false
5c19dc3a 78 * if the trust setting does not match the app's spec.
b1ab9ed8
A
79 *
80 * A match fails iff:
81 *
5c19dc3a
A
82 * -- the app has specified a field, and the cert has a spec for that
83 * field, and the two specs do not match;
b1ab9ed8
A
84 *
85 * OR
86 *
87 * -- the cert has a spec for the field and the app hasn't specified the field
88 */
89static 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
5c19dc3a 110 * specified by the app.
b1ab9ed8
A
111 */
112static bool tsCheckApp(
113 CFDataRef certApp)
114{
115 if(certApp != NULL) {
116 SecTrustedApplicationRef appRef;
117 OSStatus ortn;
118 ortn = SecTrustedApplicationCreateWithExternalRepresentation(certApp, &appRef);
119 if(ortn) {
fa7225c8 120 trustSettingsDbg("tsCheckApp: bad trustedApp data");
b1ab9ed8
A
121 return false;
122 }
123 ortn = SecTrustedApplicationValidateWithPath(appRef, NULL);
124 if(ortn) {
125 /* Not this app */
126 return false;
127 }
128 }
5c19dc3a 129
b1ab9ed8
A
130 return true;
131}
132
133static 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 }
5c19dc3a 150
b1ab9ed8
A
151 if((cku & appKeyUse) != appKeyUse) {
152 trustSettingsEvalDbg("tsCheckKeyUse: keyUse mismatch");
153 return false;
154 }
155 }
156 return true;
157}
158
159static 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 */
5c19dc3a 169 CFStringRef cfPolicyStr = CFStringCreateWithCString(NULL, appPolicyStr,
b1ab9ed8
A
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 }
5c19dc3a 176
b1ab9ed8
A
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
5c19dc3a 179
b1ab9ed8
A
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");
6b200bc3 184 CFReleaseNull(cfPolicyStr);
b1ab9ed8
A
185 return false;
186 }
5c19dc3a
A
187
188 CFStringFindAndReplace(certPolicyStrNoNULL, CFSTR("\00"),
b1ab9ed8 189 CFSTR(""), CFRangeMake(0, CFStringGetLength(certPolicyStrNoNULL)), kCFCompareBackwards);
5c19dc3a 190
b1ab9ed8
A
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
5c19dc3a
A
202/*
203 * Determine if a cert's trust settings dictionary satisfies the specified
b1ab9ed8
A
204 * usage constraints. Returns true if so.
205 * Only certs with a SecTrustSettingsResult of kSecTrustSettingsResultTrustRoot
206 * or kSecTrustSettingsResultTrustAsRoot will match.
207 */
208static 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
5c19dc3a 225 * it's used for everything.
b1ab9ed8
A
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);
5c19dc3a 233
b1ab9ed8 234 /* per-cert specs: all optional */
5c19dc3a 235 CFDataRef certPolicy = (CFDataRef)CFDictionaryGetValue(tsDict,
b1ab9ed8 236 kSecTrustSettingsPolicy);
5c19dc3a 237 CFDataRef certApp = (CFDataRef)CFDictionaryGetValue(tsDict,
b1ab9ed8 238 kSecTrustSettingsApplication);
5c19dc3a 239 CFStringRef certPolicyStr = (CFStringRef)CFDictionaryGetValue(tsDict,
b1ab9ed8 240 kSecTrustSettingsPolicyString);
5c19dc3a 241 CFNumberRef certKeyUsage = (CFNumberRef)CFDictionaryGetValue(tsDict,
b1ab9ed8 242 kSecTrustSettingsKeyUsage);
5c19dc3a 243 CFNumberRef certResultType = (CFNumberRef)CFDictionaryGetValue(tsDict,
b1ab9ed8 244 kSecTrustSettingsResult);
5c19dc3a 245
b1ab9ed8
A
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
5c19dc3a 259 /*
b1ab9ed8 260 * This is a match, take whatever SecTrustSettingsResult is here,
5c19dc3a 261 * including the default if not specified.
b1ab9ed8
A
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
5c19dc3a 290/*
b1ab9ed8
A
291 * Create initial top-level dictionary when constructing a new TrustSettings.
292 */
293static CFMutableDictionaryRef tsInitialDict()
294{
5c19dc3a 295 CFMutableDictionaryRef dict = CFDictionaryCreateMutable(NULL,
b1ab9ed8
A
296 kSecTrustRecordNumTopDictKeys,
297 &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
298
299 /* the dictionary of per-cert entries */
5c19dc3a 300 CFMutableDictionaryRef trustDict = CFDictionaryCreateMutable(NULL, 0,
b1ab9ed8
A
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 */
315static 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 */
427c49bc 326static
b1ab9ed8
A
327bool 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 }
5c19dc3a 339
b1ab9ed8
A
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
352TrustSettings::TrustSettings(SecTrustSettingsDomain domain)
5c19dc3a 353 : mPropList(NULL),
b1ab9ed8
A
354 mTrustDict(NULL),
355 mDictVersion(0),
356 mDomain(domain),
357 mDirty(false)
358{
359}
360
361
362
363#pragma mark --- Public methods ---
364
5c19dc3a 365/*
b1ab9ed8
A
366 * Normal constructor, from disk.
367 * If create is true, the absence of an on-disk TrustSettings file
5c19dc3a 368 * results in the creation of a new empty TrustSettings. If create is
b1ab9ed8
A
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
5c19dc3a 373 * that will be cached in memory long-term.
b1ab9ed8
A
374 */
375OSStatus 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};
427c49bc 385 OSStatus ortn = errSecSuccess;
b1ab9ed8
A
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:
5c19dc3a
A
392 /*
393 * Quickie optimization: if it's not there, don't try to
b1ab9ed8 394 * get it from ocspd. This is possible because the name of the
5c19dc3a 395 * admin file is hard coded, but the per-user files aren't.
b1ab9ed8
A
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;
427c49bc 416 return errSecParam;
b1ab9ed8
A
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);
5c19dc3a 438
b1ab9ed8 439 ts = t;
427c49bc 440 return errSecSuccess;
b1ab9ed8
A
441}
442
5c19dc3a 443/*
b1ab9ed8
A
444 * Create from external data, obtained by createExternal().
445 * If externalData is NULL, we'll create an empty mTrustDict.
446 */
447OSStatus 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:
427c49bc 459 return errSecParam;
b1ab9ed8
A
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;
5c19dc3a 472
b1ab9ed8 473 ts = t;
427c49bc 474 return errSecSuccess;
b1ab9ed8
A
475}
476
477
478TrustSettings::~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 */
487void 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
5c19dc3a 507/*
b1ab9ed8
A
508 * Flush property list data out to disk if dirty.
509 */
510void TrustSettings::flushToDisk()
511{
512 if(!mDirty) {
513 trustSettingsDbg("flushToDisk, domain %d, !dirty!", (int)mDomain);
5c19dc3a 514 return;
b1ab9ed8
A
515 }
516 if(mPropList == NULL) {
517 trustSettingsDbg("flushToDisk, domain %d, trimmed!", (int)mDomain);
518 assert(0);
427c49bc 519 MacOSError::throwMe(errSecInternalComponent);
b1ab9ed8
A
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);
427c49bc 527 MacOSError::throwMe(errSecInternalComponent);
b1ab9ed8
A
528 case kSecTrustSettingsDomainUser:
529 case kSecTrustSettingsDomainAdmin:
530 break;
531 }
532
533 /*
5c19dc3a
A
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
b1ab9ed8 538 * can avoid
5c19dc3a 539 * an RPC if the settings file is simply not there.
b1ab9ed8
A
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);
427c49bc 549 MacOSError::throwMe(errSecInternalComponent);
b1ab9ed8
A
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 }
5c19dc3a 557
b1ab9ed8
A
558 /* cook up auth stuff so ocspd can act on our behalf */
559 AuthorizationRef authRef;
560 OSStatus ortn;
5c19dc3a 561 ortn = AuthorizationCreate(NULL, kAuthorizationEmptyEnvironment,
b1ab9ed8
A
562 0, &authRef);
563 if(ortn) {
5c19dc3a 564 trustSettingsDbg("flushToDisk, domain %d: AuthorizationCreate returned %ld",
b1ab9ed8 565 (int)mDomain, (long)ortn);
427c49bc 566 MacOSError::throwMe(errSecInternalComponent);
b1ab9ed8
A
567 }
568 AuthorizationExternalForm authExt;
569 CSSM_DATA authBlob = {sizeof(authExt), (uint8 *)&authExt};
570 ortn = AuthorizationMakeExternalForm(authRef, &authExt);
571 if(ortn) {
5c19dc3a 572 trustSettingsDbg("flushToDisk, domain %d: AuthorizationMakeExternalForm returned %ld",
b1ab9ed8 573 (int)mDomain, (long)ortn);
427c49bc 574 ortn = errSecInternalComponent;
b1ab9ed8
A
575 goto errOut;
576 }
5c19dc3a 577
b1ab9ed8
A
578 ortn = ocspdTrustSettingsWrite(mDomain, authBlob, cssmXmlData);
579 if(ortn) {
5c19dc3a 580 trustSettingsDbg("flushToDisk, domain %d: ocspdTrustSettingsWrite returned %ld",
b1ab9ed8
A
581 (int)mDomain, (long)ortn);
582 goto errOut;
583 }
584 trustSettingsDbg("flushToDisk, domain %d: wrote to disk", (int)mDomain);
585 mDirty = false;
586errOut:
587 AuthorizationFree(authRef, 0);
588 if(ortn) {
589 MacOSError::throwMe(ortn);
590 }
591}
592
593/*
594 * Obtain external representation of TrustSettings data.
595 */
596CFDataRef 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);
427c49bc 603 MacOSError::throwMe(errSecInternalComponent);
b1ab9ed8
A
604 }
605 return xmlData;
606}
607
5c19dc3a 608/*
b1ab9ed8 609 * Evaluate specified cert. Returns true if we found a record for the cert
5c19dc3a
A
610 * matching specified constraints.
611 * Note that a true return with a value of kSecTrustSettingsResultUnspecified for
b1ab9ed8 612 * the resultType means that a cert isn't to be trusted or untrusted
5c19dc3a 613 * per se; it just means that we only found allowedErrors entries.
b1ab9ed8
A
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 */
619bool 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);
b1ab9ed8
A
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;
5c19dc3a 657
b1ab9ed8
A
658 /* this means "we found something other than allowedErrors" if true */
659 bool foundSettings = false;
5c19dc3a 660
b1ab9ed8
A
661 /* to be returned in *resultType if it ends up something other than Invalid */
662 SecTrustSettingsResult returnedResult = kSecTrustSettingsResultInvalid;
663
5c19dc3a 664 /*
b1ab9ed8
A
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
5c19dc3a 678 * it's used for everything.
b1ab9ed8
A
679 */
680 trustSettingsEvalDbg("evaluateCert: no trust settings");
681 /* the default... */
682 *resultType = kSecTrustSettingsResultTrustRoot;
683 return true;
684 }
5c19dc3a 685
b1ab9ed8
A
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);
5c19dc3a 693
b1ab9ed8 694 /* per-cert specs: all optional */
5c19dc3a 695 CFDataRef certPolicy = (CFDataRef)CFDictionaryGetValue(tsDict,
b1ab9ed8 696 kSecTrustSettingsPolicy);
5c19dc3a 697 CFDataRef certApp = (CFDataRef)CFDictionaryGetValue(tsDict,
b1ab9ed8 698 kSecTrustSettingsApplication);
5c19dc3a 699 CFStringRef certPolicyStr = (CFStringRef)CFDictionaryGetValue(tsDict,
b1ab9ed8 700 kSecTrustSettingsPolicyString);
5c19dc3a 701 CFNumberRef certKeyUsage = (CFNumberRef)CFDictionaryGetValue(tsDict,
b1ab9ed8 702 kSecTrustSettingsKeyUsage);
5c19dc3a 703 CFNumberRef certResultType = (CFNumberRef)CFDictionaryGetValue(tsDict,
b1ab9ed8 704 kSecTrustSettingsResult);
5c19dc3a 705 CFNumberRef certAllowedErr = (CFNumberRef)CFDictionaryGetValue(tsDict,
b1ab9ed8 706 kSecTrustSettingsAllowedError);
5c19dc3a 707
b1ab9ed8
A
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 }
5c19dc3a 721
b1ab9ed8
A
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);
5c19dc3a 729 allowedErrs = (CSSM_RETURN *)::realloc(allowedErrs,
b1ab9ed8
A
730 ++numAllowedErrs * sizeof(CSSM_RETURN));
731 allowedErrs[numAllowedErrs-1] = (CSSM_RETURN) s;
732 }
5c19dc3a 733
b1ab9ed8
A
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,
5c19dc3a 738 * we keep on searching, but only for additional allowed errors.
b1ab9ed8
A
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 }
5c19dc3a 755 break;
b1ab9ed8
A
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 */
775void TrustSettings::findCerts(
776 StorageManager::KeychainList &keychains,
777 CFMutableArrayRef certArray)
778{
5c19dc3a 779 findQualifiedCerts(keychains,
b1ab9ed8
A
780 true, /* findAll */
781 false, /* onlyRoots */
782 NULL, NULL, kSecTrustSettingsKeyUseAny,
783 certArray);
784}
785
786void TrustSettings::findQualifiedCerts(
787 StorageManager::KeychainList &keychains,
5c19dc3a
A
788 /*
789 * If findAll is true, all certs are returned and the subsequent
790 * qualifiers are ignored
b1ab9ed8
A
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
5c19dc3a 802 /*
b1ab9ed8 803 * a set, hopefully with a good hash function for CFData, to keep track of what's
5c19dc3a 804 * been added to the outgoing array.
b1ab9ed8
A
805 */
806 CFRef<CFMutableSetRef> certSet(CFSetCreateMutable(NULL, 0, &kCFTypeSetCallBacks));
5c19dc3a 807
b1ab9ed8 808 /* search: all certs, no attributes */
6b200bc3 809 KCCursor cursor(keychains, (SecItemClass) CSSM_DL_DB_RECORD_X509_CERTIFICATE, NULL);
b1ab9ed8
A
810 Item certItem;
811 bool found;
fa7225c8 812 unsigned int total=0, entries=0, qualified=0;
b1ab9ed8
A
813 do {
814 found = cursor->next(certItem);
815 if(!found) {
816 break;
817 }
fa7225c8 818 ++total;
6b200bc3 819
5c19dc3a
A
820 /* must convert to unified SecCertificateRef */
821 SecPointer<Certificate> certificate(static_cast<Certificate *>(&*certItem));
fa7225c8
A
822 CssmData certCssmData;
823 try {
824 certCssmData = certificate->data();
825 }
826 catch (...) {}
5c19dc3a
A
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));
5c19dc3a 832
b1ab9ed8
A
833 /* do we have an entry for this cert? */
834 CFDictionaryRef certDict = findDictionaryForCert(certRef);
835 if(certDict == NULL) {
836 continue;
837 }
fa7225c8 838 ++entries;
5c19dc3a 839
b1ab9ed8
A
840 if(!findAll) {
841 /* qualify */
842 if(!qualifyUsageWithCertDict(certDict, policyOID,
843 policyString, keyUsage, onlyRoots)) {
844 continue;
845 }
846 }
fa7225c8 847 ++qualified;
5c19dc3a 848
b1ab9ed8
A
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));
fa7225c8 857 CFDataRef cfd = cfData.get();
b1ab9ed8
A
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 */
5c19dc3a 864 CFSetAddValue(certSet, cfd);
b1ab9ed8
A
865 /* and add the SecCert to caller's array, which owns that now */
866 CFArrayAppendValue(certArray, certRef);
867 }
868 } while(found);
fa7225c8
A
869
870 trustSettingsEvalDbg("findQualifiedCerts: examined %d certs, qualified %d of %d",
871 total, qualified, entries);
b1ab9ed8
A
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
5c19dc3a 877 * (does not throw) if the cert is not present in this TrustRecord.
b1ab9ed8
A
878 */
879CFArrayRef TrustSettings::copyTrustSettings(
880 SecCertificateRef certRef)
881{
882 CFDictionaryRef certDict = NULL;
5c19dc3a 883
b1ab9ed8
A
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
5c19dc3a 898 /*
b1ab9ed8
A
899 * Convert to API-style array of dictionaries.
900 * We give the caller an array even if it's empty.
901 */
5c19dc3a 902 CFRef<CFMutableArrayRef> outArray(CFArrayCreateMutable(NULL, numSpecs,
b1ab9ed8
A
903 &kCFTypeArrayCallBacks));
904 for(CFIndex dex=0; dex<numSpecs; dex++) {
5c19dc3a 905 CFDictionaryRef diskTsDict =
b1ab9ed8
A
906 (CFDictionaryRef)CFArrayGetValueAtIndex(diskTrustSettings, dex);
907 /* already validated... */
908 assert(CFGetTypeID(diskTsDict) == CFDictionaryGetTypeID());
5c19dc3a 909
fa7225c8
A
910 CFTypeRef certPolicy = (CFTypeRef) CFDictionaryGetValue(diskTsDict, kSecTrustSettingsPolicy);
911 CFStringRef policyName = (CFStringRef)CFDictionaryGetValue(diskTsDict, kSecTrustSettingsPolicyName);
b1ab9ed8
A
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);
5c19dc3a
A
917
918 if((certPolicy == NULL) &&
b1ab9ed8
A
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
5c19dc3a 929 &kCFTypeDictionaryKeyCallBacks,
b1ab9ed8 930 &kCFTypeDictionaryValueCallBacks));
5c19dc3a 931
b1ab9ed8 932 if(certPolicy != NULL) {
b1ab9ed8 933 SecPolicyRef policyRef = NULL;
fa7225c8
A
934 if (CFDataGetTypeID() == CFGetTypeID(certPolicy)) {
935 /* convert OID as CFDataRef to SecPolicyRef */
6b200bc3 936 CSSM_OID policyOid = { int_cast<CFIndex, CSSM_SIZE>(CFDataGetLength((CFDataRef)certPolicy)),
fa7225c8
A
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);
b1ab9ed8 945 }
fa7225c8
A
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
b1ab9ed8 960 }
5c19dc3a 961
b1ab9ed8
A
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);
5c19dc3a 971 CFRelease(appRef); // owned by dictionary
b1ab9ed8 972 }
5c19dc3a 973
b1ab9ed8
A
974 /* remaining 4 are trivial */
975 if(policyStr != NULL) {
5c19dc3a 976 /*
b1ab9ed8
A
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);
5c19dc3a 982 CFRelease(str); // owned by dictionary
b1ab9ed8
A
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;
5c19dc3a 999}
b1ab9ed8
A
1000
1001CFDateRef TrustSettings::copyModDate(
1002 SecCertificateRef certRef)
1003{
1004 CFDictionaryRef certDict = NULL;
5c19dc3a 1005
b1ab9ed8
A
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
d64be36e
A
1022bool TrustSettings::contains(SecCertificateRef certRef)
1023{
1024 if(findDictionaryForCert(certRef) != NULL) {
1025 return true;
1026 }
1027 return false;
1028}
1029
b1ab9ed8 1030/*
5c19dc3a 1031 * Modify cert's trust settings, or add a new cert to the record.
b1ab9ed8
A
1032 */
1033void 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) {
5c19dc3a
A
1042 /*
1043 * Validate settings as if this were root, specifically,
b1ab9ed8
A
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));
5c19dc3a 1059
b1ab9ed8
A
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 }
5c19dc3a 1075
b1ab9ed8
A
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
5c19dc3a 1083 /*
b1ab9ed8
A
1084 * Find entry for this cert, if present.
1085 */
5c19dc3a 1086 CFMutableDictionaryRef certDict =
b1ab9ed8
A
1087 (CFMutableDictionaryRef)findDictionaryForCertHash(certHashStr);
1088 if(certDict == NULL) {
1089 /* create new dictionary */
1090 certDict = CFDictionaryCreateMutable(NULL, kSecTrustRecordNumCertDictKeys,
1091 &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1092 if(certDict == NULL) {
427c49bc 1093 MacOSError::throwMe(errSecAllocate);
b1ab9ed8
A
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);
5c19dc3a 1102
b1ab9ed8
A
1103 /* add this new cert dictionary to top-level mTrustDict */
1104 CFDictionaryAddValue(mTrustDict, static_cast<CFStringRef>(certHashStr), certDict);
5c19dc3a 1105
b1ab9ed8
A
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}
5c19dc3a 1122
b1ab9ed8 1123/*
5c19dc3a 1124 * Delete a certificate's trust settings.
b1ab9ed8
A
1125 */
1126void TrustSettings::deleteTrustSettings(
1127 SecCertificateRef certRef)
1128{
1129 CFDictionaryRef certDict = NULL;
5c19dc3a 1130
b1ab9ed8
A
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 {
5c19dc3a
A
1148 /*
1149 * Throwing this error is the only reason we don't blindly do
1150 * a CFDictionaryRemoveValue() without first doing
b1ab9ed8
A
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/*
5c19dc3a
A
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
b1ab9ed8 1166 * is needed).
5c19dc3a 1167 */
b1ab9ed8
A
1168CFDictionaryRef TrustSettings::findDictionaryForCert(
1169 SecCertificateRef certRef)
1170{
1171 CFRef<CFStringRef> certHashStr(SecTrustSettingsCertHashStrFromCert(certRef));
1172 if (certHashStr.get() == NULL)
1173 {
1174 return NULL;
1175 }
5c19dc3a 1176
fa7225c8 1177 return findDictionaryForCertHash(static_cast<CFStringRef>(certHashStr.get()));
b1ab9ed8
A
1178}
1179
1180/*
5c19dc3a 1181 * Find entry in mTrustDict given cert hash string.
b1ab9ed8
A
1182 */
1183CFDictionaryRef TrustSettings::findDictionaryForCertHash(
1184 CFStringRef certHashStr)
1185{
1186 assert(mTrustDict != NULL);
1187 return (CFDictionaryRef)CFDictionaryGetValue(mTrustDict, certHashStr);
1188}
1189
1190/*
5c19dc3a
A
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
b1ab9ed8
A
1194 * mPropList.
1195 *
1196 * We return a refcounted CFArray in any case if the incoming parameter is good.
1197 */
1198CFArrayRef 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");
427c49bc 1208 MacOSError::throwMe(errSecParam);
b1ab9ed8
A
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");
427c49bc 1224 MacOSError::throwMe(errSecParam);
b1ab9ed8 1225 }
5c19dc3a 1226
b1ab9ed8
A
1227 CFIndex numSpecs = CFArrayGetCount(tmpInArray);
1228 CFMutableArrayRef outArray = CFArrayCreateMutable(NULL, numSpecs, &kCFTypeArrayCallBacks);
1229 CSSM_OID oid;
427c49bc 1230 OSStatus ortn = errSecSuccess;
b1ab9ed8
A
1231 SecPolicyRef certPolicy;
1232 SecTrustedApplicationRef certApp;
b54c578e 1233 CFTypeRef oidData = NULL;
5c19dc3a 1234
b1ab9ed8
A
1235 /* convert */
1236 for(CFIndex dex=0; dex<numSpecs; dex++) {
fa7225c8 1237 CFStringRef policyName = NULL;
b1ab9ed8
A
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");
427c49bc 1250 ortn = errSecParam;
b1ab9ed8
A
1251 break;
1252 }
5c19dc3a 1253
b1ab9ed8
A
1254 /* policy - optional */
1255 certPolicy = (SecPolicyRef)CFDictionaryGetValue(ucDict, kSecTrustSettingsPolicy);
1256 if(certPolicy != NULL) {
1257 if(CFGetTypeID(certPolicy) != SecPolicyGetTypeID()) {
1258 trustSettingsDbg("validateAppPolicyArray: malformed certPolicy");
427c49bc 1259 ortn = errSecParam;
b1ab9ed8
A
1260 break;
1261 }
1262 ortn = SecPolicyGetOID(certPolicy, &oid);
fa7225c8
A
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) {
b1ab9ed8
A
1271 trustSettingsDbg("validateAppPolicyArray: SecPolicyGetOID error");
1272 break;
1273 }
fa7225c8 1274 policyName = SecPolicyGetName(certPolicy);
b1ab9ed8
A
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");
427c49bc 1282 ortn = errSecParam;
b1ab9ed8
A
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");
427c49bc 1297 ortn = errSecParam;
b1ab9ed8
A
1298 break;
1299 }
1300 }
1301 allowedErr = (CFNumberRef)CFDictionaryGetValue(ucDict, kSecTrustSettingsAllowedError);
1302 if(!tsIsGoodCfNum(allowedErr)) {
1303 trustSettingsDbg("validateAppPolicyArray: malformed allowedErr");
427c49bc 1304 ortn = errSecParam;
b1ab9ed8
A
1305 break;
1306 }
1307 resultType = (CFNumberRef)CFDictionaryGetValue(ucDict, kSecTrustSettingsResult);
1308 if(!tsIsGoodCfNum(resultType, &resultNum)) {
1309 trustSettingsDbg("validateAppPolicyArray: malformed resultType");
427c49bc 1310 ortn = errSecParam;
b1ab9ed8
A
1311 break;
1312 }
6b200bc3 1313 result = (SecTrustSettingsResult) resultNum;
b1ab9ed8
A
1314 /* validate result later */
1315
1316 keyUsage = (CFNumberRef)CFDictionaryGetValue(ucDict, kSecTrustSettingsKeyUsage);
1317 if(!tsIsGoodCfNum(keyUsage)) {
1318 trustSettingsDbg("validateAppPolicyArray: malformed keyUsage");
427c49bc 1319 ortn = errSecParam;
b1ab9ed8
A
1320 break;
1321 }
5c19dc3a
A
1322
1323 if(!oidData && !appData && !policyStr &&
b1ab9ed8
A
1324 !allowedErr && !resultType && !keyUsage) {
1325 /* nothing here - weird, but legal - skip it */
1326 continue;
1327 }
5c19dc3a 1328
b1ab9ed8 1329 /* create dictionary for this usageConstraint */
5c19dc3a
A
1330 CFMutableDictionaryRef outDict = CFDictionaryCreateMutable(NULL,
1331 2,
1332 &kCFTypeDictionaryKeyCallBacks,
b1ab9ed8
A
1333 &kCFTypeDictionaryValueCallBacks);
1334 if(oidData) {
1335 CFDictionaryAddValue(outDict, kSecTrustSettingsPolicy, oidData);
b54c578e 1336 CFReleaseNull(oidData); // owned by dictionary
b1ab9ed8 1337 }
fa7225c8
A
1338 if(policyName) {
1339 CFDictionaryAddValue(outDict, kSecTrustSettingsPolicyName, policyName);
1340 /* still owned by ucDict */
1341 }
b1ab9ed8
A
1342 if(appData) {
1343 CFDictionaryAddValue(outDict, kSecTrustSettingsApplication, appData);
5c19dc3a 1344 CFRelease(appData); // owned by dictionary
b1ab9ed8
A
1345 }
1346 if(policyStr) {
1347 CFDictionaryAddValue(outDict, kSecTrustSettingsPolicyString, policyStr);
1348 /* still owned by ucDict */
1349 }
1350 if(allowedErr) {
1351 CFDictionaryAddValue(outDict, kSecTrustSettingsAllowedError, allowedErr);
1352 }
fa7225c8 1353
5c19dc3a 1354 ortn = errSecSuccess;
fa7225c8 1355
b1ab9ed8
A
1356 if(resultType) {
1357 /* let's be really picky on this one */
1358 switch(result) {
1359 case kSecTrustSettingsResultInvalid:
427c49bc 1360 ortn = errSecParam;
b1ab9ed8
A
1361 break;
1362 case kSecTrustSettingsResultTrustRoot:
1363 if(!isSelfSigned) {
1364 trustSettingsDbg("validateAppPolicyArray: TrustRoot, !isSelfSigned");
427c49bc 1365 ortn = errSecParam;
b1ab9ed8
A
1366 }
1367 break;
1368 case kSecTrustSettingsResultTrustAsRoot:
1369 if(isSelfSigned) {
1370 trustSettingsDbg("validateAppPolicyArray: TrustAsRoot, isSelfSigned");
427c49bc 1371 ortn = errSecParam;
b1ab9ed8
A
1372 }
1373 break;
1374 case kSecTrustSettingsResultDeny:
1375 case kSecTrustSettingsResultUnspecified:
1376 break;
1377 default:
1378 trustSettingsDbg("validateAppPolicyArray: bogus resultType");
427c49bc 1379 ortn = errSecParam;
b1ab9ed8
A
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");
427c49bc 1391 ortn = errSecParam;
b1ab9ed8
A
1392 break;
1393 }
1394 }
fa7225c8 1395
b1ab9ed8
A
1396 if(keyUsage) {
1397 CFDictionaryAddValue(outDict, kSecTrustSettingsKeyUsage, keyUsage);
1398 }
5c19dc3a 1399
b1ab9ed8
A
1400 /* append dictionary to output */
1401 CFArrayAppendValue(outArray, outDict);
1402 /* array owns the dictionary now */
1403 CFRelease(outDict);
5c19dc3a 1404
b1ab9ed8 1405 } /* for each usage constraint dictionary */
5c19dc3a 1406
b54c578e 1407 CFReleaseNull(oidData);
b1ab9ed8
A
1408 CFRelease(tmpInArray);
1409 if(ortn) {
1410 CFRelease(outArray);
1411 MacOSError::throwMe(ortn);
1412 }
1413 return outArray;
1414}
1415
5c19dc3a 1416/*
b1ab9ed8 1417 * Validate an trust settings array obtained from disk.
5c19dc3a 1418 * Returns true if OK, else returns false.
b1ab9ed8
A
1419 */
1420bool TrustSettings::validateTrustSettingsArray(
1421 CFArrayRef trustSettings)
1422{
1423 CFIndex numSpecs = CFArrayGetCount(trustSettings);
1424 for(CFIndex dex=0; dex<numSpecs; dex++) {
5c19dc3a 1425 CFDictionaryRef ucDict = (CFDictionaryRef)CFArrayGetValueAtIndex(trustSettings,
b1ab9ed8
A
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/*
5c19dc3a
A
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.
b1ab9ed8
A
1469 */
1470void 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 */
5c19dc3a 1499
b1ab9ed8
A
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 }
5c19dc3a 1508
b1ab9ed8
A
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 }
5c19dc3a
A
1522
1523 /*
b1ab9ed8
A
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 }
5c19dc3a 1555
b1ab9ed8
A
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 }
5c19dc3a 1569
b1ab9ed8
A
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 }
5c19dc3a 1582
b1ab9ed8
A
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
5c19dc3a
A
1596/*
1597 * Obtain non-normalized issuer and serial number for specified cert, both
1598 * returned as CFDataRefs owned by caller.
b1ab9ed8
A
1599 */
1600void TrustSettings::copyIssuerAndSerial(
1601 SecCertificateRef certRef,
1602 CFDataRef *issuer, /* optional, RETURNED */
1603 CFDataRef *serial) /* RETURNED */
1604{
5c19dc3a 1605 CFRef<SecCertificateRef> certificate = SecCertificateCreateItemImplInstance(certRef);
5c19dc3a
A
1606
1607 SecPointer<Certificate> cert = Certificate::required(certificate);
b1ab9ed8 1608 CSSM_DATA_PTR fieldVal;
5c19dc3a
A
1609
1610 if(issuer != NULL) {
b1ab9ed8
A
1611 fieldVal = cert->copyFirstFieldValue(CSSMOID_X509V1IssuerNameStd);
1612 *issuer = CFDataCreate(NULL, fieldVal->Data, fieldVal->Length);
1613 cert->releaseFieldValue(CSSMOID_X509V1IssuerNameStd, fieldVal);
1614 }
5c19dc3a 1615
b1ab9ed8
A
1616 fieldVal = cert->copyFirstFieldValue(CSSMOID_X509V1SerialNumber);
1617 *serial = CFDataCreate(NULL, fieldVal->Data, fieldVal->Length);
1618 cert->releaseFieldValue(CSSMOID_X509V1SerialNumber, fieldVal);
1619}
1620
1621void TrustSettings::abort(
1622 const char *why,
1623 OSStatus err)
1624{
1625 Syslog::error("TrustSettings: %s", why);
1626 MacOSError::throwMe(err);
1627}
1628