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