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