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