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