]> git.saurik.com Git - apple/security.git/blame - OSX/libsecurity_keychain/lib/TrustSettings.cpp
Security-58286.70.7.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"
31#include "SecTrustSettings.h"
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>
53#include <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
1022/*
5c19dc3a 1023 * Modify cert's trust settings, or add a new cert to the record.
b1ab9ed8
A
1024 */
1025void TrustSettings::setTrustSettings(
1026 SecCertificateRef certRef,
1027 CFTypeRef trustSettingsDictOrArray)
1028{
1029 /* to validate, we need to know if the cert is self-signed */
1030 OSStatus ortn;
1031 Boolean isSelfSigned = false;
1032
1033 if(certRef == kSecTrustSettingsDefaultRootCertSetting) {
5c19dc3a
A
1034 /*
1035 * Validate settings as if this were root, specifically,
b1ab9ed8
A
1036 * kSecTrustSettingsResultTrustRoot (explicitly or by
1037 * default) is OK.
1038 */
1039 isSelfSigned = true;
1040 }
1041 else {
1042 ortn = SecCertificateIsSelfSigned(certRef, &isSelfSigned);
1043 if(ortn) {
1044 MacOSError::throwMe(ortn);
1045 }
1046 }
1047
1048 /* caller's app/policy spec OK? */
1049 CFRef<CFArrayRef> trustSettings(validateApiTrustSettings(
1050 trustSettingsDictOrArray, isSelfSigned));
5c19dc3a 1051
b1ab9ed8
A
1052 /* caller is responsible for ensuring these */
1053 assert(mPropList != NULL);
1054 assert(mDomain != kSecTrustSettingsDomainSystem);
1055
1056 /* extract issuer and serial number from the cert, if it's a cert */
1057 CFRef<CFDataRef> issuer;
1058 CFRef<CFDataRef> serial;
1059 if(certRef != kSecTrustSettingsDefaultRootCertSetting) {
1060 copyIssuerAndSerial(certRef, issuer.take(), serial.take());
1061 }
1062 else {
1063 UInt8 dummy;
1064 issuer = CFDataCreate(NULL, &dummy, 0);
1065 serial = CFDataCreate(NULL, &dummy, 0);
1066 }
5c19dc3a 1067
b1ab9ed8
A
1068 /* SHA1 digest as string */
1069 CFRef<CFStringRef> certHashStr(SecTrustSettingsCertHashStrFromCert(certRef));
1070 if(!certHashStr) {
1071 trustSettingsDbg("TrustSettings::setTrustSettings: CertHashStrFromCert error");
1072 MacOSError::throwMe(errSecItemNotFound);
1073 }
1074
5c19dc3a 1075 /*
b1ab9ed8
A
1076 * Find entry for this cert, if present.
1077 */
5c19dc3a 1078 CFMutableDictionaryRef certDict =
b1ab9ed8
A
1079 (CFMutableDictionaryRef)findDictionaryForCertHash(certHashStr);
1080 if(certDict == NULL) {
1081 /* create new dictionary */
1082 certDict = CFDictionaryCreateMutable(NULL, kSecTrustRecordNumCertDictKeys,
1083 &kCFCopyStringDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
1084 if(certDict == NULL) {
427c49bc 1085 MacOSError::throwMe(errSecAllocate);
b1ab9ed8
A
1086 }
1087 CFDictionaryAddValue(certDict, kTrustRecordIssuer, issuer);
1088 CFDictionaryAddValue(certDict, kTrustRecordSerialNumber, serial);
1089 if(CFArrayGetCount(trustSettings) != 0) {
1090 /* skip this if the settings array is empty */
1091 CFDictionaryAddValue(certDict, kTrustRecordTrustSettings, trustSettings);
1092 }
1093 tsSetModDate(certDict);
5c19dc3a 1094
b1ab9ed8
A
1095 /* add this new cert dictionary to top-level mTrustDict */
1096 CFDictionaryAddValue(mTrustDict, static_cast<CFStringRef>(certHashStr), certDict);
5c19dc3a 1097
b1ab9ed8
A
1098 /* mTrustDict owns the dictionary now */
1099 CFRelease(certDict);
1100 }
1101 else {
1102 /* update */
1103 tsSetModDate(certDict);
1104 if(CFArrayGetCount(trustSettings) != 0) {
1105 CFDictionarySetValue(certDict, kTrustRecordTrustSettings, trustSettings);
1106 }
1107 else {
1108 /* empty settings array: remove from dictionary */
1109 CFDictionaryRemoveValue(certDict, kTrustRecordTrustSettings);
1110 }
1111 }
1112 mDirty = true;
1113}
5c19dc3a 1114
b1ab9ed8 1115/*
5c19dc3a 1116 * Delete a certificate's trust settings.
b1ab9ed8
A
1117 */
1118void TrustSettings::deleteTrustSettings(
1119 SecCertificateRef certRef)
1120{
1121 CFDictionaryRef certDict = NULL;
5c19dc3a 1122
b1ab9ed8
A
1123 /* caller is responsible for ensuring these */
1124 assert(mPropList != NULL);
1125 assert(mDomain != kSecTrustSettingsDomainSystem);
1126
1127 /* SHA1 digest as string */
1128 CFRef<CFStringRef> certHashStr(SecTrustSettingsCertHashStrFromCert(certRef));
1129 if(!certHashStr) {
1130 MacOSError::throwMe(errSecItemNotFound);
1131 }
1132
1133 /* present in top-level mTrustDict? */
1134 certDict = findDictionaryForCertHash(certHashStr);
1135 if(certDict != NULL) {
1136 CFDictionaryRemoveValue(mTrustDict, static_cast<CFStringRef>(certHashStr));
1137 mDirty = true;
1138 }
1139 else {
5c19dc3a
A
1140 /*
1141 * Throwing this error is the only reason we don't blindly do
1142 * a CFDictionaryRemoveValue() without first doing
b1ab9ed8
A
1143 * findDictionaryForCertHash().
1144 */
1145 trustSettingsDbg("TrustSettings::deleteRoot: cert dictionary not found");
1146 MacOSError::throwMe(errSecItemNotFound);
1147 }
1148}
1149
1150#pragma mark --- Private methods ---
1151
1152/*
5c19dc3a
A
1153 * Find a given cert's entry in the top-level mTrustDict. Return the
1154 * entry as a dictionary. Returned dictionary is not refcounted.
1155 * The mutability of the returned dictionary is the same as the mutability
1156 * of the underlying StickRecord::mPropList, which the caller is just
1157 * going to have to know (and cast accordingly if a mutable dictionary
b1ab9ed8 1158 * is needed).
5c19dc3a 1159 */
b1ab9ed8
A
1160CFDictionaryRef TrustSettings::findDictionaryForCert(
1161 SecCertificateRef certRef)
1162{
1163 CFRef<CFStringRef> certHashStr(SecTrustSettingsCertHashStrFromCert(certRef));
1164 if (certHashStr.get() == NULL)
1165 {
1166 return NULL;
1167 }
5c19dc3a 1168
fa7225c8 1169 return findDictionaryForCertHash(static_cast<CFStringRef>(certHashStr.get()));
b1ab9ed8
A
1170}
1171
1172/*
5c19dc3a 1173 * Find entry in mTrustDict given cert hash string.
b1ab9ed8
A
1174 */
1175CFDictionaryRef TrustSettings::findDictionaryForCertHash(
1176 CFStringRef certHashStr)
1177{
1178 assert(mTrustDict != NULL);
1179 return (CFDictionaryRef)CFDictionaryGetValue(mTrustDict, certHashStr);
1180}
1181
1182/*
5c19dc3a
A
1183 * Validate incoming trust settings, which may be NULL, a dictionary, or
1184 * an array of dictionaries. Convert from the API-style dictionaries
1185 * to the internal style suitable for writing to disk as part of
b1ab9ed8
A
1186 * mPropList.
1187 *
1188 * We return a refcounted CFArray in any case if the incoming parameter is good.
1189 */
1190CFArrayRef TrustSettings::validateApiTrustSettings(
1191 CFTypeRef trustSettingsDictOrArray,
1192 Boolean isSelfSigned)
1193{
1194 CFArrayRef tmpInArray = NULL;
1195
1196 if(trustSettingsDictOrArray == NULL) {
1197 /* trivial case, only valid for roots */
1198 if(!isSelfSigned) {
1199 trustSettingsDbg("validateApiUsageConstraints: !isSelfSigned, no settings");
427c49bc 1200 MacOSError::throwMe(errSecParam);
b1ab9ed8
A
1201 }
1202 return CFArrayCreate(NULL, NULL, 0, &kCFTypeArrayCallBacks);
1203 }
1204 else if(CFGetTypeID(trustSettingsDictOrArray) == CFDictionaryGetTypeID()) {
1205 /* array-ize it */
1206 tmpInArray = CFArrayCreate(NULL, &trustSettingsDictOrArray, 1,
1207 &kCFTypeArrayCallBacks);
1208 }
1209 else if(CFGetTypeID(trustSettingsDictOrArray) == CFArrayGetTypeID()) {
1210 /* as is, refcount - we'll release later */
1211 tmpInArray = (CFArrayRef)trustSettingsDictOrArray;
1212 CFRetain(tmpInArray);
1213 }
1214 else {
1215 trustSettingsDbg("validateApiUsageConstraints: bad trustSettingsDictOrArray");
427c49bc 1216 MacOSError::throwMe(errSecParam);
b1ab9ed8 1217 }
5c19dc3a 1218
b1ab9ed8
A
1219 CFIndex numSpecs = CFArrayGetCount(tmpInArray);
1220 CFMutableArrayRef outArray = CFArrayCreateMutable(NULL, numSpecs, &kCFTypeArrayCallBacks);
1221 CSSM_OID oid;
427c49bc 1222 OSStatus ortn = errSecSuccess;
b1ab9ed8
A
1223 SecPolicyRef certPolicy;
1224 SecTrustedApplicationRef certApp;
5c19dc3a 1225
b1ab9ed8
A
1226 /* convert */
1227 for(CFIndex dex=0; dex<numSpecs; dex++) {
fa7225c8
A
1228 CFTypeRef oidData = NULL;
1229 CFStringRef policyName = NULL;
b1ab9ed8
A
1230 CFDataRef appData = NULL;
1231 CFStringRef policyStr = NULL;
1232 CFNumberRef allowedErr = NULL;
1233 CFNumberRef resultType = NULL;
1234 CFNumberRef keyUsage = NULL;
1235 SInt32 resultNum;
1236 SecTrustSettingsResult result;
1237
1238 /* each element is a dictionary */
1239 CFDictionaryRef ucDict = (CFDictionaryRef)CFArrayGetValueAtIndex(tmpInArray, dex);
1240 if(CFGetTypeID(ucDict) != CFDictionaryGetTypeID()) {
1241 trustSettingsDbg("validateAppPolicyArray: malformed usageConstraint dictionary");
427c49bc 1242 ortn = errSecParam;
b1ab9ed8
A
1243 break;
1244 }
5c19dc3a 1245
b1ab9ed8
A
1246 /* policy - optional */
1247 certPolicy = (SecPolicyRef)CFDictionaryGetValue(ucDict, kSecTrustSettingsPolicy);
1248 if(certPolicy != NULL) {
1249 if(CFGetTypeID(certPolicy) != SecPolicyGetTypeID()) {
1250 trustSettingsDbg("validateAppPolicyArray: malformed certPolicy");
427c49bc 1251 ortn = errSecParam;
b1ab9ed8
A
1252 break;
1253 }
1254 ortn = SecPolicyGetOID(certPolicy, &oid);
fa7225c8
A
1255 if (ortn) {
1256 /* newer policies don't have CSSM OIDs but they do have string OIDs */
1257 oidData = CFRetain(SecPolicyGetOidString(certPolicy));
1258 } else {
1259 oidData = CFDataCreate(NULL, oid.Data, oid.Length);
1260 }
1261
1262 if (!oidData) {
b1ab9ed8
A
1263 trustSettingsDbg("validateAppPolicyArray: SecPolicyGetOID error");
1264 break;
1265 }
fa7225c8 1266 policyName = SecPolicyGetName(certPolicy);
b1ab9ed8
A
1267 }
1268
1269 /* application - optional */
1270 certApp = (SecTrustedApplicationRef)CFDictionaryGetValue(ucDict, kSecTrustSettingsApplication);
1271 if(certApp != NULL) {
1272 if(CFGetTypeID(certApp) != SecTrustedApplicationGetTypeID()) {
1273 trustSettingsDbg("validateAppPolicyArray: malformed certApp");
427c49bc 1274 ortn = errSecParam;
b1ab9ed8
A
1275 break;
1276 }
1277 ortn = SecTrustedApplicationCopyExternalRepresentation(certApp, &appData);
1278 if(ortn) {
1279 trustSettingsDbg("validateAppPolicyArray: "
1280 "SecTrustedApplicationCopyExternalRepresentation error");
1281 break;
1282 }
1283 }
1284
1285 policyStr = (CFStringRef)CFDictionaryGetValue(ucDict, kSecTrustSettingsPolicyString);
1286 if(policyStr != NULL) {
1287 if(CFGetTypeID(policyStr) != CFStringGetTypeID()) {
1288 trustSettingsDbg("validateAppPolicyArray: malformed policyStr");
427c49bc 1289 ortn = errSecParam;
b1ab9ed8
A
1290 break;
1291 }
1292 }
1293 allowedErr = (CFNumberRef)CFDictionaryGetValue(ucDict, kSecTrustSettingsAllowedError);
1294 if(!tsIsGoodCfNum(allowedErr)) {
1295 trustSettingsDbg("validateAppPolicyArray: malformed allowedErr");
427c49bc 1296 ortn = errSecParam;
b1ab9ed8
A
1297 break;
1298 }
1299 resultType = (CFNumberRef)CFDictionaryGetValue(ucDict, kSecTrustSettingsResult);
1300 if(!tsIsGoodCfNum(resultType, &resultNum)) {
1301 trustSettingsDbg("validateAppPolicyArray: malformed resultType");
427c49bc 1302 ortn = errSecParam;
b1ab9ed8
A
1303 break;
1304 }
6b200bc3 1305 result = (SecTrustSettingsResult) resultNum;
b1ab9ed8
A
1306 /* validate result later */
1307
1308 keyUsage = (CFNumberRef)CFDictionaryGetValue(ucDict, kSecTrustSettingsKeyUsage);
1309 if(!tsIsGoodCfNum(keyUsage)) {
1310 trustSettingsDbg("validateAppPolicyArray: malformed keyUsage");
427c49bc 1311 ortn = errSecParam;
b1ab9ed8
A
1312 break;
1313 }
5c19dc3a
A
1314
1315 if(!oidData && !appData && !policyStr &&
b1ab9ed8
A
1316 !allowedErr && !resultType && !keyUsage) {
1317 /* nothing here - weird, but legal - skip it */
1318 continue;
1319 }
5c19dc3a 1320
b1ab9ed8 1321 /* create dictionary for this usageConstraint */
5c19dc3a
A
1322 CFMutableDictionaryRef outDict = CFDictionaryCreateMutable(NULL,
1323 2,
1324 &kCFTypeDictionaryKeyCallBacks,
b1ab9ed8
A
1325 &kCFTypeDictionaryValueCallBacks);
1326 if(oidData) {
1327 CFDictionaryAddValue(outDict, kSecTrustSettingsPolicy, oidData);
5c19dc3a 1328 CFRelease(oidData); // owned by dictionary
b1ab9ed8 1329 }
fa7225c8
A
1330 if(policyName) {
1331 CFDictionaryAddValue(outDict, kSecTrustSettingsPolicyName, policyName);
1332 /* still owned by ucDict */
1333 }
b1ab9ed8
A
1334 if(appData) {
1335 CFDictionaryAddValue(outDict, kSecTrustSettingsApplication, appData);
5c19dc3a 1336 CFRelease(appData); // owned by dictionary
b1ab9ed8
A
1337 }
1338 if(policyStr) {
1339 CFDictionaryAddValue(outDict, kSecTrustSettingsPolicyString, policyStr);
1340 /* still owned by ucDict */
1341 }
1342 if(allowedErr) {
1343 CFDictionaryAddValue(outDict, kSecTrustSettingsAllowedError, allowedErr);
1344 }
fa7225c8 1345
5c19dc3a 1346 ortn = errSecSuccess;
fa7225c8 1347
b1ab9ed8
A
1348 if(resultType) {
1349 /* let's be really picky on this one */
1350 switch(result) {
1351 case kSecTrustSettingsResultInvalid:
427c49bc 1352 ortn = errSecParam;
b1ab9ed8
A
1353 break;
1354 case kSecTrustSettingsResultTrustRoot:
1355 if(!isSelfSigned) {
1356 trustSettingsDbg("validateAppPolicyArray: TrustRoot, !isSelfSigned");
427c49bc 1357 ortn = errSecParam;
b1ab9ed8
A
1358 }
1359 break;
1360 case kSecTrustSettingsResultTrustAsRoot:
1361 if(isSelfSigned) {
1362 trustSettingsDbg("validateAppPolicyArray: TrustAsRoot, isSelfSigned");
427c49bc 1363 ortn = errSecParam;
b1ab9ed8
A
1364 }
1365 break;
1366 case kSecTrustSettingsResultDeny:
1367 case kSecTrustSettingsResultUnspecified:
1368 break;
1369 default:
1370 trustSettingsDbg("validateAppPolicyArray: bogus resultType");
427c49bc 1371 ortn = errSecParam;
b1ab9ed8
A
1372 break;
1373 }
1374 if(ortn) {
1375 break;
1376 }
1377 CFDictionaryAddValue(outDict, kSecTrustSettingsResult, resultType);
1378 }
1379 else {
1380 /* no resultType; default of TrustRoot only valid for root */
1381 if(!isSelfSigned) {
1382 trustSettingsDbg("validateAppPolicyArray: default result, !isSelfSigned");
427c49bc 1383 ortn = errSecParam;
b1ab9ed8
A
1384 break;
1385 }
1386 }
fa7225c8 1387
b1ab9ed8
A
1388 if(keyUsage) {
1389 CFDictionaryAddValue(outDict, kSecTrustSettingsKeyUsage, keyUsage);
1390 }
5c19dc3a 1391
b1ab9ed8
A
1392 /* append dictionary to output */
1393 CFArrayAppendValue(outArray, outDict);
1394 /* array owns the dictionary now */
1395 CFRelease(outDict);
5c19dc3a 1396
b1ab9ed8 1397 } /* for each usage constraint dictionary */
5c19dc3a 1398
b1ab9ed8
A
1399 CFRelease(tmpInArray);
1400 if(ortn) {
1401 CFRelease(outArray);
1402 MacOSError::throwMe(ortn);
1403 }
1404 return outArray;
1405}
1406
5c19dc3a 1407/*
b1ab9ed8 1408 * Validate an trust settings array obtained from disk.
5c19dc3a 1409 * Returns true if OK, else returns false.
b1ab9ed8
A
1410 */
1411bool TrustSettings::validateTrustSettingsArray(
1412 CFArrayRef trustSettings)
1413{
1414 CFIndex numSpecs = CFArrayGetCount(trustSettings);
1415 for(CFIndex dex=0; dex<numSpecs; dex++) {
5c19dc3a 1416 CFDictionaryRef ucDict = (CFDictionaryRef)CFArrayGetValueAtIndex(trustSettings,
b1ab9ed8
A
1417 dex);
1418 if(CFGetTypeID(ucDict) != CFDictionaryGetTypeID()) {
1419 trustSettingsDbg("validateAppPolicyArray: malformed app/policy dictionary");
1420 return false;
1421 }
1422 CFDataRef certPolicy = (CFDataRef)CFDictionaryGetValue(ucDict, kSecTrustSettingsPolicy);
1423 if((certPolicy != NULL) && (CFGetTypeID(certPolicy) != CFDataGetTypeID())) {
1424 trustSettingsDbg("validateAppPolicyArray: malformed certPolicy");
1425 return false;
1426 }
1427 CFDataRef certApp = (CFDataRef)CFDictionaryGetValue(ucDict, kSecTrustSettingsApplication);
1428 if((certApp != NULL) && (CFGetTypeID(certApp) != CFDataGetTypeID())) {
1429 trustSettingsDbg("validateAppPolicyArray: malformed certApp");
1430 return false;
1431 }
1432 CFStringRef policyStr = (CFStringRef)CFDictionaryGetValue(ucDict, kSecTrustSettingsPolicyString);
1433 if((policyStr != NULL) && (CFGetTypeID(policyStr) != CFStringGetTypeID())) {
1434 trustSettingsDbg("validateAppPolicyArray: malformed policyStr");
1435 return false;
1436 }
1437 CFNumberRef cfNum = (CFNumberRef)CFDictionaryGetValue(ucDict, kSecTrustSettingsAllowedError);
1438 if(!tsIsGoodCfNum(cfNum)) {
1439 trustSettingsDbg("validateAppPolicyArray: malformed allowedErr");
1440 return false;
1441 }
1442 cfNum = (CFNumberRef)CFDictionaryGetValue(ucDict, kSecTrustSettingsResult);
1443 if(!tsIsGoodCfNum(cfNum)) {
1444 trustSettingsDbg("validateAppPolicyArray: malformed resultType");
1445 return false;
1446 }
1447 cfNum = (CFNumberRef)CFDictionaryGetValue(ucDict, kSecTrustSettingsKeyUsage);
1448 if(!tsIsGoodCfNum(cfNum)) {
1449 trustSettingsDbg("validateAppPolicyArray: malformed keyUsage");
1450 return false;
1451 }
1452 } /* for each usageConstraint dictionary */
1453 return true;
1454}
1455
1456/*
5c19dc3a
A
1457 * Validate mPropList after it's read from disk or supplied as an external
1458 * representation. Allows subsequent use of mTrustDict to proceed with
1459 * relative impunity.
b1ab9ed8
A
1460 */
1461void TrustSettings::validatePropList(bool trim)
1462{
1463 /* top level dictionary */
1464 if(!mPropList) {
1465 trustSettingsDbg("TrustSettings::validatePropList missing mPropList");
1466 abort("missing propList", errSecInvalidTrustedRootRecord);
1467 }
1468
1469 if(CFGetTypeID(mPropList) != CFDictionaryGetTypeID()) {
1470 trustSettingsDbg("TrustSettings::validatePropList: malformed mPropList");
1471 abort("malformed propList", errSecInvalidTrustedRootRecord);
1472 }
1473
1474 /* That dictionary has two entries */
1475 CFNumberRef cfVers = (CFNumberRef)CFDictionaryGetValue(mPropList, kTrustRecordVersion);
1476 if((cfVers == NULL) || (CFGetTypeID(cfVers) != CFNumberGetTypeID())) {
1477 trustSettingsDbg("TrustSettings::validatePropList: malformed version");
1478 abort("malformed version", errSecInvalidTrustedRootRecord);
1479 }
1480 if(!CFNumberGetValue(cfVers, kCFNumberSInt32Type, &mDictVersion)) {
1481 trustSettingsDbg("TrustSettings::validatePropList: malformed version");
1482 abort("malformed version", errSecInvalidTrustedRootRecord);
1483 }
1484 if((mDictVersion > kSecTrustRecordVersionCurrent) ||
1485 (mDictVersion == kSecTrustRecordVersionInvalid)) {
1486 trustSettingsDbg("TrustSettings::validatePropList: incompatible version");
1487 abort("incompatible version", errSecInvalidTrustedRootRecord);
1488 }
1489 /* other backwards-compatibility handling done later, if needed, per mDictVersion */
5c19dc3a 1490
b1ab9ed8
A
1491 mTrustDict = (CFMutableDictionaryRef)CFDictionaryGetValue(mPropList, kTrustRecordTrustList);
1492 if(mTrustDict != NULL) {
1493 CFRetain(mTrustDict);
1494 }
1495 if((mTrustDict == NULL) || (CFGetTypeID(mTrustDict) != CFDictionaryGetTypeID())) {
1496 trustSettingsDbg("TrustSettings::validatePropList: malformed mTrustDict");
1497 abort("malformed TrustArray", errSecInvalidTrustedRootRecord);
1498 }
5c19dc3a 1499
b1ab9ed8
A
1500 /* grind through the per-cert entries */
1501 CFIndex numCerts = CFDictionaryGetCount(mTrustDict);
1502 const void *dictKeys[numCerts];
1503 const void *dictValues[numCerts];
1504 CFDictionaryGetKeysAndValues(mTrustDict, dictKeys, dictValues);
1505
1506 for(CFIndex dex=0; dex<numCerts; dex++) {
1507 /* get per-cert dictionary */
1508 CFMutableDictionaryRef certDict = (CFMutableDictionaryRef)dictValues[dex];
1509 if((certDict == NULL) || (CFGetTypeID(certDict) != CFDictionaryGetTypeID())) {
1510 trustSettingsDbg("TrustSettings::validatePropList: malformed certDict");
1511 abort("malformed certDict", errSecInvalidTrustedRootRecord);
1512 }
5c19dc3a
A
1513
1514 /*
b1ab9ed8
A
1515 * That dictionary has exactly four entries.
1516 * If we're trimming, all we need is the actual trust settings.
1517 */
1518
1519 /* issuer */
1520 CFDataRef cfd = (CFDataRef)CFDictionaryGetValue(certDict, kTrustRecordIssuer);
1521 if(cfd == NULL) {
1522 trustSettingsDbg("TrustSettings::validatePropList: missing issuer");
1523 abort("missing issuer", errSecInvalidTrustedRootRecord);
1524 }
1525 if(CFGetTypeID(cfd) != CFDataGetTypeID()) {
1526 trustSettingsDbg("TrustSettings::validatePropList: malformed issuer");
1527 abort("malformed issuer", errSecInvalidTrustedRootRecord);
1528 }
1529 if(trim) {
1530 CFDictionaryRemoveValue(certDict, kTrustRecordIssuer);
1531 }
1532
1533 /* serial number */
1534 cfd = (CFDataRef)CFDictionaryGetValue(certDict, kTrustRecordSerialNumber);
1535 if(cfd == NULL) {
1536 trustSettingsDbg("TrustSettings::validatePropList: missing serial number");
1537 abort("missing serial number", errSecInvalidTrustedRootRecord);
1538 }
1539 if(CFGetTypeID(cfd) != CFDataGetTypeID()) {
1540 trustSettingsDbg("TrustSettings::validatePropList: malformed serial number");
1541 abort("malformed serial number", errSecInvalidTrustedRootRecord);
1542 }
1543 if(trim) {
1544 CFDictionaryRemoveValue(certDict, kTrustRecordSerialNumber);
1545 }
5c19dc3a 1546
b1ab9ed8
A
1547 /* modification date */
1548 CFDateRef modDate = (CFDateRef)CFDictionaryGetValue(certDict, kTrustRecordModDate);
1549 if(modDate == NULL) {
1550 trustSettingsDbg("TrustSettings::validatePropList: missing modDate");
1551 abort("missing modDate", errSecInvalidTrustedRootRecord);
1552 }
1553 if(CFGetTypeID(modDate) != CFDateGetTypeID()) {
1554 trustSettingsDbg("TrustSettings::validatePropList: malformed modDate");
1555 abort("malformed modDate", errSecInvalidTrustedRootRecord);
1556 }
1557 if(trim) {
1558 CFDictionaryRemoveValue(certDict, kTrustRecordModDate);
1559 }
5c19dc3a 1560
b1ab9ed8
A
1561 /* the actual trust settings */
1562 CFArrayRef trustSettings = (CFArrayRef)CFDictionaryGetValue(certDict,
1563 kTrustRecordTrustSettings);
1564 if(trustSettings == NULL) {
1565 /* optional; this cert's entry is good */
1566 continue;
1567 }
1568 if(CFGetTypeID(trustSettings) != CFArrayGetTypeID()) {
1569 trustSettingsDbg("TrustSettings::validatePropList: malformed useConstraint"
1570 "array");
1571 abort("malformed useConstraint array", errSecInvalidTrustedRootRecord);
1572 }
5c19dc3a 1573
b1ab9ed8
A
1574 /* Now validate the usageConstraint array contents */
1575 if(!validateTrustSettingsArray(trustSettings)) {
1576 abort("malformed useConstraint array", errSecInvalidTrustedRootRecord);
1577 }
1578 } /* for each cert dictionary in top-level array */
1579
1580 if(trim) {
1581 /* we don't need the top-level dictionary any more */
1582 CFRelease(mPropList);
1583 mPropList = NULL;
1584 }
1585}
1586
5c19dc3a
A
1587/*
1588 * Obtain non-normalized issuer and serial number for specified cert, both
1589 * returned as CFDataRefs owned by caller.
b1ab9ed8
A
1590 */
1591void TrustSettings::copyIssuerAndSerial(
1592 SecCertificateRef certRef,
1593 CFDataRef *issuer, /* optional, RETURNED */
1594 CFDataRef *serial) /* RETURNED */
1595{
5c19dc3a 1596 CFRef<SecCertificateRef> certificate = SecCertificateCreateItemImplInstance(certRef);
5c19dc3a
A
1597
1598 SecPointer<Certificate> cert = Certificate::required(certificate);
b1ab9ed8 1599 CSSM_DATA_PTR fieldVal;
5c19dc3a
A
1600
1601 if(issuer != NULL) {
b1ab9ed8
A
1602 fieldVal = cert->copyFirstFieldValue(CSSMOID_X509V1IssuerNameStd);
1603 *issuer = CFDataCreate(NULL, fieldVal->Data, fieldVal->Length);
1604 cert->releaseFieldValue(CSSMOID_X509V1IssuerNameStd, fieldVal);
1605 }
5c19dc3a 1606
b1ab9ed8
A
1607 fieldVal = cert->copyFirstFieldValue(CSSMOID_X509V1SerialNumber);
1608 *serial = CFDataCreate(NULL, fieldVal->Data, fieldVal->Length);
1609 cert->releaseFieldValue(CSSMOID_X509V1SerialNumber, fieldVal);
1610}
1611
1612void TrustSettings::abort(
1613 const char *why,
1614 OSStatus err)
1615{
1616 Syslog::error("TrustSettings: %s", why);
1617 MacOSError::throwMe(err);
1618}
1619