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